Labsco
ogham-mcp logo

ogham-mcp

β˜… 110

from ogham-mcp

Persistent shared memory for AI agents. Hybrid search (pgvector + tsvector), knowledge graph, cognitive scoring - 97.2% Recall@10 on LongMemEval

πŸ”₯πŸ”₯πŸ”₯πŸ”₯βœ“ VerifiedFreeAdvanced setup

Ogham MCP

Ogham (pronounced "OH-um") -- persistent, searchable shared memory for AI coding agents. Works across clients.

License: MIT Docker Python 3.13+ PyPI

Contents

Retrieval quality

85.8% QA accuracy on the AMB benchmark harness (500 questions, April 2026) -- 429/500 questions answered correctly using GPT-5-mini with reasoning, evaluated by Gemini 2.5 Flash Lite as a strict judge. Retrieval R@10: 99.5%. AMB is the standardised evaluation harness built by the Vectorize team (creators of Hindsight). Thanks to Nicolo and the Vectorize team for making the harness open.

Previously: 91.8% on our internal LongMemEval benchmark pipeline (gpt-5.4-mini reader, rubric judge). The AMB number is lower because AMB uses a stricter substring-matching judge -- see the full write-up for methodology differences.

0.554 nugget score on BEAM 100K (400 questions across 10 memory abilities, ICLR 2026), using the paper's exact judge prompt from Appendix G. The published baseline is 0.358 (Llama-4-Maverick + LIGHT). Retrieval R@10: 0.737. Seven of nine categories beat the paper. Full write-up.

End-to-end QA accuracy on LongMemEval (retrieval + LLM reads and answers):

SystemAccuracyArchitecture
OMEGA95.4%Classification + extraction pipeline
Observational Memory (Mastra)94.9%Observation extraction + GPT-5-mini
Ogham v0.9.285.8%Verbatim + read-time extraction + gpt-5-mini (AMB harness, strict judge)
Ogham v0.9.191.8%Hybrid search + context engineering + gpt-5.4-mini (internal benchmark)
Hindsight (Vectorize)91.4%4 memory types + Gemini-3
Zep (Graphiti)71.2%Temporal knowledge graph + GPT-4o
Mem049.0%RAG-based

Retrieval only (R@10 -- no LLM in the search loop):

SystemR@10Architecture
Ogham97.2%1 SQL query (pgvector + tsvector CCF hybrid search)
LongMemEval paper baseline78.4%Session decomposition + fact-augmented keys

Other retrieval systems that report similar R@10 numbers typically use cross-encoder reranking, NLI verification, knowledge graph enrichment, and LLM-as-a-judge pipelines. Ogham reaches 97.2% with one Postgres query. Optional FlashRank reranking is available for self-hosters who want extra ranking precision.

These tables measure different things. QA accuracy tests whether the full system (retrieval + LLM) produces the correct answer. R@10 tests whether retrieval alone finds the right memories. Ogham is a retrieval engine -- it finds the memories, your LLM reads them.

CategoryR@10Questions
single-session-assistant100%56
knowledge-update100%78
single-session-user98.6%70
multi-session97.3%133
single-session-preference96.7%30
temporal-reasoning93.5%133

Full breakdown: ogham-mcp.dev/features

The problem

AI coding agents forget everything between sessions. Switch from Claude Code to Cursor to Kiro to OpenCode and context is lost. Decisions, gotchas, architectural patterns -- gone. You end up repeating yourself, re-explaining your codebase, re-debugging the same issues.

Ogham gives your agents a shared memory that persists across sessions and clients.

SSE transport (multi-agent)

By default, Ogham runs in stdio mode -- each MCP client spawns its own server process. For multiple agents sharing one server, use SSE mode:

Copy & paste β€” that's it
ogham serve --transport sse --port 8742

The server runs as a persistent background process. All clients connect to the same instance -- one database pool, one embedding cache, shared memory.

Client config for SSE (any MCP client):

Copy & paste β€” that's it
{
  "mcpServers": {
    "ogham": {
      "url": "http://127.0.0.1:8742/sse"
    }
  }
}

Health check at http://127.0.0.1:8742/health (cached, sub-10ms).

Configure via env vars (OGHAM_TRANSPORT=sse, OGHAM_HOST, OGHAM_PORT) or CLI flags. The init wizard (ogham init) walks through SSE setup if you choose it.

Entry points

Ogham has two entry points:

  • ogham -- the CLI. Use this for ogham init, ogham health, ogham search, and other commands you run yourself. Running ogham with no arguments starts the MCP server.
  • ogham-serve -- starts the MCP server directly. This is what MCP clients should call. When you run uvx ogham-mcp, it invokes ogham-serve.

CLI

Copy & paste β€” that's it
ogham init                      # Interactive setup wizard
ogham health                    # Check database + embedding provider
ogham config                    # Show runtime configuration (secrets masked)
ogham store "some fact"         # Store a memory
ogham search "query"            # Search memories (hybrid: semantic + keyword)
ogham search "q" --json         # JSON output for scripting
ogham search "q" --tags "a,b"   # Filter by comma-separated tags
ogham list                      # List recent memories
ogham list --json               # JSON output
ogham delete <id>               # Delete a memory by ID
ogham use <profile>             # Switch default profile
ogham profiles                  # List profiles and counts
ogham stats                     # Profile statistics
ogham export -o backup.json     # Export memories (JSON)
ogham export --format markdown  # Export as Obsidian-compatible markdown
ogham export --format okf       # Export as Open Knowledge Format v0.1 bundle
ogham import backup.json        # Import a JSON export
ogham import <okf-bundle-dir>   # Import an OKF bundle directory (auto-detected)
ogham cleanup                   # Remove expired memories
ogham hooks install             # Auto-detect client + configure hooks
ogham hooks recall              # Read from the stone (load project context)
ogham hooks inscribe            # Carve into the stone (capture activity)
ogham hooks inscribe --dry-run  # Preview hook memory without storing
ogham serve                     # Start MCP server (stdio, default)
ogham serve --transport sse     # Start SSE server on port 8742
ogham openapi                   # Generate OpenAPI spec

Multi-profile search

Search across multiple profiles in a single query (v0.8.5+):

Copy & paste β€” that's it
# MCP tool
hybrid_search(query="architecture decisions", profiles=["work", "shared"])

# Python library
from ogham.service import search_memories_enriched
results = search_memories_enriched(
    query="architecture decisions",
    profile="work",
    profiles=["work", "shared", "project-alpha"],
)

When profiles is set, results include memories from all listed profiles with a profile field showing which profile each result came from.

MCP tools

Memory operations

ToolDescriptionKey parameters
store_memoryStore a new memory with embeddingcontent (required), source, tags[], auto_link
store_decisionStore an architectural decisiondecision, reasoning, alternatives[], tags[]
store_preferenceStore a user preference with strength metadatapreference, subject, alternatives[], strength
store_factStore a factual statement with confidence and citationfact, subject, confidence, source_citation
store_eventStore an event with temporal and participant metadataevent, when, participants[], location
update_memoryUpdate content of existing memorymemory_id, content, tags[]
delete_memoryDelete a memory by IDmemory_id
reinforce_memoryIncrease confidence scorememory_id
contradict_memoryDecrease confidence scorememory_id

Search

ToolDescriptionKey parameters
hybrid_searchCombined semantic + full-text search (RRF)query, limit, tags[], graph_depth, profiles[], extract_facts
list_recentList recent memorieslimit, profile
find_relatedFind memories related to a given onememory_id, limit

Knowledge graph

ToolDescriptionKey parameters
link_unlinkedAuto-link memories by embedding similaritythreshold, limit
explore_knowledgeTraverse the knowledge graphmemory_id, depth, direction
suggest_connectionsFind hidden connections via shared entitiesmemory_id, min_shared_entities, limit

Typed-edge graph (v0.16)

Structural, typed relationships for two-fact join queries. Full detail in /docs/typed-edges/.

ToolDescriptionKey parameters
store_tripleWrite a typed edge against a controlled predicate vocabulary; supersedes the prior current edge for the same subject + predicate + objectsubject, predicate, object, profile, source_memory_id
query_joinWalk a typed predicate path from a start entity; returns the entities (BFS order), edges, and citations along the path -- no fuzzy rankingstart_entity, predicate_path[], hop_limit (required), direction

Importers

ToolDescriptionKey parameters
import_linearImport Linear issues as memories, read-only, deduped by tracker id (v0.16)see /docs/import-linear/

Profiles

ToolDescriptionKey parameters
switch_profileSwitch active memory profileprofile
current_profileShow active profile--
list_profilesList all profiles with counts--
set_profile_ttlSet auto-expiry for a profileprofile, ttl_days

Import / export

ToolDescriptionKey parameters
export_profileExport all memories in active profileformat (json, markdown, or okf), include_viewer (default true for OKF)
import_memories_toolImport a JSON export string OR auto-detect an OKF bundle directory by pathdata, dedup_threshold

--format okf writes an Open Knowledge Format v0.1 conformant bundle: a directory of one-markdown-file-per-memory with YAML frontmatter, a bundle-root index.md declaring okf_version: "0.1", and a self-contained viewer.html (Cytoscape.js graph, opens with file://, no server or CDN needed). Round-trip preserves UUID, content, tags, source, and metadata; the embedding is regenerated on import. Pass include_viewer=false to skip the HTML graph. See docs/okf-format.md for the round-trip contract.

Maintenance

ToolDescriptionKey parameters
re_embed_allRe-embed all memories (after switching providers)--
compress_old_memoriesCondense old inactive memories (full text to summary to tags)--
cleanup_expiredRemove expired memories (TTL)--
health_checkCheck database and embedding connectivity--
get_configShow runtime configuration with masked secrets--
get_statsMemory counts, sources, tags, and profile health (orphans, decay, tagging)--
get_cache_statsEmbedding cache hit rates--

Wiki layer

The wiki layer turns a tag full of related memories into a synthesized markdown page. Run compile_wiki on a tag, get back a summarized topic; the cache invalidates automatically when underlying memories change. Four MCP tools cover the lifecycle:

ToolDescriptionKey parameters
compile_wikiCompile a tag's memories into a synthesized markdown page (LLM call, cached)topic, provider, model, force
query_topic_summaryRead the cached page for a topic without recomputingtopic
walk_knowledgeDirection-aware graph walk from a known memory along relationship edgesstart_id, depth, direction (outgoing, incoming, both), min_strength, relationship_types
lint_wikiHealth report: contradictions, orphans, stale lifecycle, stale summaries, summary driftstable_days, sample_size, include_drift

The wiki layer needs an LLM. Synthesis is the LLM step that turns a list of memories into a coherent page; embeddings alone aren't enough. You can run that LLM locally (Ollama with llama3.2, vLLM, or any OpenAI-compatible local server) or in the cloud (Gemini, OpenAI, Anthropic, Mistral, Groq, OpenRouter). Local keeps everything private and free; cloud generally writes more polished prose at the cost of a few cents per compile.

Set the default with LLM_PROVIDER and LLM_MODEL in your environment (e.g. LLM_PROVIDER=gemini + LLM_MODEL=gemini-2.5-flash, or LLM_PROVIDER=ollama + LLM_MODEL=llama3.2). Override per call with compile_wiki(topic=..., provider=..., model=...). The provider/model is stamped into the resulting page's frontmatter, so you can re-compile the same topic with a different LLM and see how the synthesis changes.

compile_wiki short-circuits when the source memories haven't changed since the last compile -- the call is effectively free if nothing has moved. Pass force=True to bypass that check (useful for re-compiling with a different model on the same source set).

The wiki layer requires migrations 028, 030, and 031 applied to your database. See Database setup for details.

Obsidian export

Snapshot your wiki layer to a folder of Obsidian-compatible markdown files. One .md per topic with full YAML frontmatter, plus a README.md index. Wikilinks between topics are auto-detected and wrapped in [[brackets]] for Obsidian's graph view.

Copy & paste β€” that's it
ogham export-obsidian /path/to/vault
ogham export-obsidian /path/to/vault --profile work --force

The export is read-only -- it writes files but never reads them back. Edits in Obsidian stay in Obsidian; re-run the export to refresh the snapshot. By design the exporter refuses to write into a directory that already contains files it didn't create; pass --force to override that guardrail.

Full guide with frontmatter reference, troubleshooting, and screenshots: obsidian export docs.

Open Knowledge Format

Round-trip portability for your memories. Ogham reads and writes Open Knowledge Format (OKF) v0.1, the markdown-based interchange format Google Cloud published in June 2026. The same bundle is portable to any other OKF-speaking tool -- Google's Knowledge Catalog, a colleague's homegrown reader, or your own future system.

Copy & paste β€” that's it
# Export your profile as an OKF v0.1 bundle directory
ogham export --format okf

# Round-trip it back (auto-detected as an OKF bundle)
ogham import ogham-okf-<profile>-<timestamp>

The bundle is a directory tree:

Copy & paste β€” that's it
ogham-okf-<profile>-<timestamp>/
β”œβ”€β”€ index.md                     # declares okf_version: "0.1"
β”œβ”€β”€ viewer.html                  # self-contained Cytoscape.js graph (opens with file://)
└── memories/
    β”œβ”€β”€ <slug>-<uuid8>.md        # one markdown file per memory
    └── ...

Each memory file has YAML frontmatter (type, id, tags, timestamp, source, optional title) and the memory body as markdown. type: is derived from the first type:X tag alphabetically (falling back to Memory). Round-trip preserves UUID, content, tags, source, and any extension metadata; the embedding is regenerated on import.

The viewer.html is a 425 KB self-contained file with Cytoscape.js (MIT) vendored inline -- no server, no internet, no CDN. Open it in any browser via file:// to see your memories as a graph coloured by type, with edges following intra-bundle markdown links. Pass include_viewer=false to skip it.

Import behaviour:

  • Memories with the id: extension upsert by UUID (idempotent re-imports).
  • Memories without id: insert as new; the count surfaces as missing_id_count in the result.
  • The importer requires a bundle-root index.md with okf_version declared so pointing it at a random directory fails fast.

User-facing docs: docs/okf-format.md.

Importing existing memory

From Claude Code (auto-memory MD files)

Claude Code's auto-memory system writes per-project notes under ~/.claude/projects/<encoded-cwd>/memory/. Each note is a markdown file with YAML frontmatter (name, description, type, optional originSessionId). Pull them into Ogham:

Copy & paste β€” that's it
ogham import-claude-code ~/.claude/projects/<encoded-cwd>/memory \
    --project ogham --dedup 0.8

Each parseable file becomes one Ogham memory tagged source:claude-code-memory + type:<frontmatter type> + project:<inferred or explicit>. MEMORY.md (the index) and dotfiles are skipped. Files without recognisable frontmatter log a warning and are skipped.

The encoded-cwd directory naming is lossy on hyphenated repo names: openbrain-sharedmemory decodes to sharedmemory because every / and - becomes the same separator. Pass --project NAME to override the inferred tag and keep your project tags consistent.

The importer respects inscribe_enabled() β€” --no-inscribe and OGHAM_INSCRIBE_ENABLED=false skip the import. Re-runs are dedup-safe via the --dedup cosine threshold (default 0.8). MCP tool: import_claude_code_memories(directory, project_tag=...).

From Claude.ai (conversation data export)

Anthropic offers a first-party data export at Settings β†’ Privacy β†’ Request your data. After ~24-48h you receive a ZIP containing conversations.json. Pull it into Ogham:

Copy & paste β€” that's it
ogham import-claude-ai ~/Downloads/data-<id>-batch-0000 --profile claude-ai

Accepts the ZIP itself, the unzipped directory, or conversations.json directly. Each (human, assistant) turn-pair becomes one memory with the assistant turn as content (the signal you'll search on) and the human prompt in metadata.user_prompt (recoverable for context). Tagging: source:claude-ai, claude-conversation:<title-slug>, optional project:<tag>.

A conservative smart filter drops pleasantry exchanges; pass --no-smart-filter to keep them. Use --since 2026-01-01 to import only recent conversations, or --mode raw for one memory per individual message instead of per turn-pair.

To get an LLM-distilled summary of an imported conversation, call compile_wiki(topic="claude-conversation:<slug>") via MCP. Verbatim ingest plus on-demand synthesis means you keep the raw turns and get a digest, without the importer making LLM calls upfront. The summary regenerates whenever the source memories change.

UUIDs from the export land in metadata so re-importing the same export later only adds new turns. MCP tool: import_claude_ai_export(path, profile, mode=...).

Bulk imports skip per-memory enrichment

The Claude Code, Claude.ai, and JSON importers all write through import_memories, which embeds + dedups + inserts in batches but skips per-memory entity extraction and auto-link β€” a 600-memory import would otherwise run thousands of secondary RPCs. Imported memories are immediately searchable via embedding + keyword. To populate the entity graph after a bulk import, run ogham backfill-entities --profile <name> (see Entity graph below).

From a JSON export

Copy & paste β€” that's it
ogham export --profile work > backup.json
ogham import backup.json --profile work-restored

Round-trips the full memory schema (content, embeddings, tags, metadata, lifecycle state). Useful for migrating between deployments or seeding a fresh profile from another.

Entity graph

Ogham extracts entity tags from every stored memory at ingest (people, files, errors, locations, projects -- pure regex, no LLM). v0.14 added the live wire-up so those tags also populate a separate entity graph used for spreading-activation retrieval and cross-memory connection suggestions.

After applying migration 036 on an existing deployment, run a one-shot backfill to populate historical memories:

Copy & paste β€” that's it
ogham backfill-entities --profile work

The backfill walks the memories table, runs the entity extractor, and links each memory to its entities via link_memory_entities. ON CONFLICT DO NOTHING makes re-runs free. New writes after v0.14 are linked automatically; the backfill only matters for memories created before the upgrade.

Once the graph is populated:

  • suggest_connections returns memories that share entities with an anchor memory (was always empty before).
  • entity_graph_density returns real numbers (count of distinct entities and edges per profile).
  • The spread_entity_activation_memories RPC walks the bipartite memory/entity graph for context-rich retrieval.

MCP tool: backfill_entities(profile=None, batch_size=200).

Skills

Ogham ships with three workflow skills in skills/ that wire up common MCP tool chains. Install them in Claude Code, Cursor, or any client that supports skills.

SkillTriggers onWhat it does
ogham-research"remember this", "store this finding", "save what we learned"Checks for duplicates via hybrid_search before storing. Auto-tags with a consistent scheme (type:decision, type:gotcha, etc.). Uses store_decision for architectural choices.
ogham-recall"what do I know about X", "find related", "context for this project"Chains hybrid_search, find_related, and explore_knowledge to surface connections. Bootstraps session context at project start.
ogham-maintain"memory stats", "clean up my memory", "export my brain"Runs health_check, get_stats, cleanup_expired, re_embed_all, link_unlinked. Warns before irreversible operations.

Skills call existing MCP tools -- they don't replace them. The MCP server must be connected for skills to work.

Install all three with npx:

Copy & paste β€” that's it
npx skills add ogham-mcp/ogham-mcp

Or install a specific skill:

Copy & paste β€” that's it
npx skills add ogham-mcp/ogham-mcp --skill ogham-recall

Manual install (copy from a local clone):

Copy & paste β€” that's it
cp -r skills/ogham-research skills/ogham-recall skills/ogham-maintain ~/.claude/skills/

Scoring and condensing

Ogham goes beyond storing and retrieving. Three server-side features run automatically, no configuration needed.

Novelty detection. When you store a memory, Ogham checks how similar it is to what you already have. Redundant content gets a lower novelty score and ranks quieter in search results. You can still find it, but it won't push out more useful memories.

Content signal scoring. Memories that mention decisions, errors, architecture, or contain code blocks get a higher signal score. A debug session where you fixed a real bug ranks above a casual note about a meeting. The scoring is pure regex, no LLM involved.

Automatic condensing. Old memories that nobody accesses gradually shrink. Full text becomes a summary of key sentences, then a one-line description with tags. The original is always preserved and can be restored if the memory becomes relevant again. Run compress_old_memories manually or on a schedule. High-importance and frequently-accessed memories resist condensing.

Entity enrichment

Every memory is automatically enriched at ingest with structured entity tags -- no LLM calls, pure regex and dictionary matching across 18 languages.

Six entity categories. Events (wedding, concert, meeting), activities (hiking, coding, cooking), emotions (frustrated, happy, relieved), relationships (sister, boss, colleague), quantities (3 books, 5 miles), and locations (Berlin, Tokyo -- via GeoNames database).

18 languages. English, German, French, Spanish, Italian, Portuguese, Brazilian Portuguese, Dutch, Polish, Russian, Ukrainian, Turkish, Arabic, Hindi, Japanese, Korean, Chinese, and Irish. Each language includes common inflected forms (case endings, verb tenses, lenition) so "svadΚΉbu" matches "svadΚΉba" in Russian and "bhainis" matches "bainis" in Irish.

Timeline table. Search results include a chronological timeline with pre-computed "days ago" and memory ID cross-references. Helps LLM readers answer temporal questions without doing date arithmetic.

Lost in the Middle reordering. Search results are reordered so the highest-relevance memories appear at the start and end of the context, where LLMs pay the most attention (Liu et al., 2023).

Cross-encoder reranking

Optional FlashRank cross-encoder reranking for self-hosters who want better ranking precision. Adds ~300ms per search on CPU.

After Ogham's hybrid search returns candidates, FlashRank (ms-marco-MiniLM-L-12-v2, 21MB) rescores each result against the query using deeper token-level attention. The final score blends retrieval ranking with cross-encoder ranking.

BEAM benchmark impact: R@10 0.69 β†’ 0.70, MRR +8pp. Biggest gain: temporal reasoning 0.84 β†’ 0.98. Full results.

Install and enable:

Copy & paste β€” that's it
pip install ogham-mcp[rerank]
# or: uv add ogham-mcp[rerank]

export RERANK_ENABLED=true
export RERANK_ALPHA=0.55   # 55% cross-encoder, 45% retrieval score

The model downloads on first use (~21MB). Self-hosters who want speed over precision leave it off (the default).

ONNX local embeddings

Run BGE-M3 locally with ONNX Runtime -- dense and sparse vectors in a single model pass, no API calls, no GPU required. Contributed by @ninthhousestudios.

The ONNX provider produces 1024-dim dense vectors plus neural sparse vectors. When sparse vectors are available, Ogham automatically uses three-signal Reciprocal Rank Fusion (dense + FTS + sparse) instead of the default two-signal path.

Install and configure:

Copy & paste β€” that's it
pip install ogham-mcp[onnx]

# Download the model (~2.2GB)
ogham download-model bge-m3

export EMBEDDING_PROVIDER=onnx
export EMBEDDING_DIM=1024

Your database schema must use vector(1024) for the embedding column. Performance on CPU: ~0.3s per short text, ~10s for long documents (5K+ chars). RSS: ~4.3GB peak.

The ONNX provider is designed for self-hosters who want zero API costs. Cloud users should use Gemini or Voyage for lower latency.

Architecture

Ogham runs as an MCP server over stdio or SSE. Your AI client connects to it like any other MCP tool.

Copy & paste β€” that's it
AI Client (Claude Code, Cursor, Kiro, OpenCode, ...)
    |
    | stdio (MCP protocol)
    |
Ogham MCP Server
    |
    | HTTPS (Supabase REST API) or direct connection (Postgres)
    |
PostgreSQL + pgvector

Memories are stored as rows with vector embeddings. Search combines pgvector cosine similarity with PostgreSQL full-text search using Reciprocal Rank Fusion (RRF) -- position-based, score-agnostic fusion that handles different score scales correctly. Optional FlashRank cross-encoder reranking adds a second pass for self-hosters. The Supabase backend uses postgrest-py directly (not the full Supabase SDK) for a lightweight dependency footprint.

The knowledge graph uses a memory_relationships table with recursive CTEs for traversal -- no separate graph database.

Research foundations

Ogham's retrieval pipeline combines established information retrieval and cognitive science techniques:

  • Hybrid search -- Reciprocal Rank Fusion (Cormack, Clarke & Butt, SIGIR 2009) combining dense vector similarity (pgvector) with BM25-style keyword matching (PostgreSQL tsvector). Two independent retrieval systems, rank-fused without score normalisation.

  • Entity overlap boost -- memories sharing named entities with the query receive a bounded relevance boost (up to 1.4x), inspired by entity-linking literature (Kolitsas et al., CoNLL 2018). Entity extraction covers 18 languages via YAML-based word lists with no LLM in the write path.

  • Matryoshka embeddings -- flexible dimensionality via Matryoshka Representation Learning (Kusupati et al., NeurIPS 2022). Embedding providers (OpenAI, Voyage, Gemini, Ollama) produce native-dimension vectors truncated to 512d, enabling provider-portable storage without re-embedding.

  • Temporal diversity re-ranking -- density-gated soft penalty preventing semantic clustering on a single time period, extending Maximal Marginal Relevance principles (Carbonell & Goldstein, SIGIR 1998). Only activates when the top-k results are temporally concentrated, leaving well-distributed results untouched.

  • ACT-R importance scoring -- cognitive-architecture-inspired memory weighting based on recency, access frequency, and surprise (Anderson & Lebiere, 1998). Frequently accessed memories stay sharp, rarely accessed ones fade, disputed ones drop in ranking without deletion.

  • Hebbian decay and potentiation -- memories that are not accessed lose importance over time (5% per 30-day idle period). Memories accessed 10+ times become "potentiated" with a slower decay rate (1% per 30 days), simulating long-term potentiation. Based on Hebb's learning rule (Hebb, 1949) and computational models of synaptic plasticity (Bi & Poo, 2001). Importance serves as a multiplier in the relevance formula -- decayed memories sink in rankings but remain retrievable (floor at 0.05). Original importance is preserved in metadata for recovery. Run as a batch job via ogham decay or pg_cron.

  • Memory lifecycle (v0.11.0): FRESH / STABLE / EDITING. Every memory now has an explicit stage tracked in a dedicated memory_lifecycle table. New memories land at fresh. The session-start hook sweeps aged fresh memories to stable when they clear an importance-or-surprise gate and have dwelled long enough. Retrieval opens a 30-minute editing window on the returned memories so follow-up update_memory calls refine recent thoughts in place; windows auto-close on the next sweep. Memories retrieved together also strengthen their pairwise graph edges (eta=0.01 per co-retrieval, capped at 1.0). The design draws on three lines of prior art: Hebbian co-activation (Hebb, 1949), the hybrid exponential-then-power-law forgetting curve characterised by Wixted (2004) building on Ebbinghaus (1885), and the memory reconsolidation window from neuroscience (Nader, Schafe & LeDoux, 2000) for the editing-on-retrieval mechanic. Stage state lives in its own table so transitions do not touch the HNSW vector index.

  • Spreading activation -- when a search hits one memory, activation spreads along relationship edges to pull in connected memories that wouldn't have matched on their own. Integrated into cross-reference, ordering, and summary queries. Density-adaptive weighting means sparse graphs lean harder on graph signal, dense graphs rely more on retrieval score. Inspired by Collins & Loftus (1975) semantic network theory.

  • Contradiction detection -- when a new memory has opposite polarity to a high-similarity existing memory, Ogham automatically creates a contradicts relationship edge. Polarity detection uses negation markers across 18 languages loaded from YAML word lists. Contradicted memories are not deleted -- the edge records that the newer memory superseded the older one.

  • Read-time fact extraction -- query-aware extraction at retrieval time preserves verbatim storage for auditability, contrasting with write-time compression approaches. Verbatim storage ensures the ground truth is always available for re-extraction with different questions later -- a design choice informed by alignment considerations in persistent agent memory (Anthropic, arXiv:2510.05179). Supports local models via Ollama for full data sovereignty.

  • Append-only audit trails -- every store, search, delete, and update operation is logged to an audit_log table in the same Postgres instance. Designed for GDPR Article 15 subject access requests and cost governance. Fields align with OTEL GenAI Semantic Conventions. Query via ogham audit CLI. No extra infrastructure -- runs in the same database as memories.

Documentation

Full docs and integration guides at ogham-mcp.dev.

Credits

Inspired by Nate B Jones and his work on persistent AI memory.

Named after Ogham, the ancient Irish alphabet carved into stone -- the original persistent memory.

License

MIT