Skip to main content
Glama

Memoose: A Dual-Path Memory System for Proactive Agents


Contents

What is Memoose

Memoose is a dual-path memory system for proactive agents. Memory survives the session and survives switching agents. It is found two ways: by search when the agent asks, and by recommendation when it does not. An engine keeps a typed knowledge graph on your machine; a harness of skills, hooks and tools teaches the model your host already runs how to use it.

It is built for long-lived project work: decisions, conventions and ownership facts that must stay correct for months, each with an evidence pointer back to its source.

Vision

Memory is upkeep. Facts are written as they surface. memoose maintain sweeps the store into one worklist of things to judge and decides nothing itself; a model makes every call, on a small subagent that costs neither your attention nor the conversation's turns.

Search and recommendation are the two ways anything gets found. Search answers a question you thought to ask. Recommendation surfaces what you did not. A search-only memory stays silent unless the agent already suspects something is there. Memoose does both: recall, and a hint before each prompt.

The context an agent most often lacks is procedural. It knows what things are and still runs steps out of order, skips a check, or repeats a step that already failed. Memoose stores procedures as a graph, after Google's Procedural Graphs: steps as nodes, transitions carrying a condition, an advice and a pitfall. The agent declares where it is, reads the transitions two hops out, and decides. When the session ends with an outcome, every transition it took counts it, so the next run learns from the last.

Read more: Vision.

Quick start

Python 3.11 or newer, nothing else:

pip install memoose            # or: pipx install memoose, or uvx memoose --help

Store a fact, ask a question, look at the graph:

memoose remember "Bao:Person --owns--> auth-service:System" -e "user said 2026-09-18"
memoose remember "auth-service --uses--> PostgreSQL:Technology" -e "repo://src/db.py#L1-L20"
memoose recall "who owns auth and what does it run on"
memoose view                   # the graph in your browser, nothing uploaded

A fact is source[:Type] --relation--> target[:Type]. Give the :Type the first time an entity appears; after that the name is enough. Every fact takes -e/--evidence, --valid-from and --desc. Later:

memoose maintain               # one worklist: conflicts, duplicates, sessions to distil
memoose history auth-service   # every change to an entity or fact, by whom and why

Memory lives in ~/.memoose/<dataset>.sqlite: one dataset per project plus a user dataset for facts that hold everywhere. MEMOOSE_DATA_DIR moves it. Full command table under CLI.

Give your agent memory

The CLI is enough for an agent with a shell. To add the skills, on Claude Code and Codex the hooks, and on Claude Code the memory-keeper subagent:

memoose install claude         # or: codex | opencode | cursor
memoose status                 # what is installed where

install copies the skills into the host. On Claude Code it also registers the hooks in ~/.claude/settings.json and drops the agent into ~/.claude/agents/; on Codex it registers them in ~/.codex/hooks.json, and Codex asks you to trust them once in /hooks. It is user-scoped; --project . scopes it to one repository; uninstall <host> reverses it. No MCP server is wired unless the agent has no shell: install <host> --mcp adds uvx memoose serve, which needs uv.

On Claude Code the plugin is the simplest route and keeps one copy of everything:

/plugin marketplace add AndrewNgo-ini/memoose
/plugin install memoose@memoose
git clone https://github.com/AndrewNgo-ini/memoose.git && cd memoose && uv sync
uv run memoose install claude          # skills, hooks and agent from this checkout
claude --plugin-dir .                  # or load the checkout as a plugin
uv sync --extra fastembed              # local embeddings (a keyless hash fallback is used otherwise)
uv sync --extra ontology               # full RDF parsing
uv run pytest

Onboarding. Ask your agent to onboard Memoose. The memoose-onboard skill checks what works on this host, installs what is missing, then fills the project's memory from its README, docs and git log so the next session starts with context.

How Memoose works

Two layers. A deterministic engine: a knowledge graph behind a CLI and 26 MCP tools, no model. A harness of skills, hooks and a subagent that carries the judgment, run by the model your host already has.

Usage

Tools

26 MCP tools; every capability is a tool call on any MCP host.

area

tools

ontology

describe_ontology, add_entity_type, import_ontology (OWL/RDF/Turtle), declare_functional_relations

write

remember, mark_contradiction, supersede, merge_entities, cross_connect, set_bucket_summary, forget

read

recall, guidance, contradiction_candidates, history, memify_candidates, global_context, list_datasets

sessions

session_start, session_add_turn, session_set_context, session_get, session_timeline, publish_lessons, session_end

Skills

skill

teaches the host model

memoose

when to recall; how to extract facts with evidence, store procedures, shape the ontology

memoose-sessions

the working loop: position and guidance, context sections, outcome, distilling lessons

memoose-upkeep

judging what the store surfaces: contradictions, duplicates, connections, stale summaries

memoose-onboard

check what works, install what is missing, then fill this project's memory from its docs and history

CLI

Memory operations, the same ones the tools expose:

command

what it does

memoose recall "who owns billing"

search memory; --mode, --limit, --superseded, --json

memoose remember "bao:Person --owns--> auth:System"

store a fact; --desc, -e, --valid-from; --when, --do, --avoid on a transition; --stdin for a JSON batch

memoose guidance "run the test suite"

what comes next from a procedure: transitions two hops out, with how past runs ended

memoose history auth-service

the provenance ledger for an entity or fact

memoose contradictions [names]

hotspots and open contradictions to judge

memoose ontology · memoose datasets · memoose context

entity types and stats · memory scopes · global context

memoose session start|turn|context|get|timeline|lessons|end

session lifecycle; turn --at <procedure> declares position, end --outcome records how it went

memoose maintain

the periodic pass: everything that needs judging, in one worklist

memoose dismiss <key> --reason "..."

decline a candidate so it is not proposed again

memoose view

the graph in your browser as one HTML file (--superseded draws history dashed)

memoose forget --entity X

delete an entity, fact, session or dataset

memoose tool <name> --stdin

any remaining tool, arguments as JSON on stdin

Output is compact text; over --max-inline (2000 chars) it goes to a file whose path is printed. --json gives the exact tool payload, never cut. Setup:

command

what it does

memoose install <host>

skills, hooks and the agent into a host (--project, --mcp)

memoose uninstall <host>

reverse it

memoose status

what is installed where

memoose serve

the stdio MCP server, for a host that launches one

Benchmarks

Memoose has no model of its own, so its score is inseparable from the model driving it. We report the number that matches how it is meant to run: a small, fast model throughout.

LoCoMo is the standard conversational-memory benchmark: long multi-session conversations, then questions about them. One model answers from what the memory system retrieves; another grades. We run mem0's protocol with their prompts verbatim, so the memory system is the only difference.

Our run

Claude Haiku 4.5 as answerer and judge, all 1,540 questions: 90.4% correct at 4,699 mean prompt tokens ($88.55, September 2026). A reference point, not a competitive entry.

category

questions

score

single-hop

841

93.5

temporal

321

89.7

multi-hop

282

88.7

open-domain

96

70.8

Open-domain is the weak category: its gold answers are single turns that never reach the retrieved context.

What others report

Every figure is self-reported by its vendor on a different model, judge and retrieval setup. They are not comparable with each other or with ours; they are context.

system

reported

notes

ZeroMemory

96.1

unverified

Zep

94.7

third-party testing found 75.1

ByteRover

92.2 / 96.1

two conflicting figures published

mem0

92.5

single-hop 94.6, multi-hop 95.4, temporal 92.5, open-domain 82.3; 6,956 prompt tokens

Memoose (Haiku 4.5)

90.4

the run above; per-category scores, CI, cost and raw rows published

Dakera

88.2

no LLM reranking

full context, no memory

~73

the whole conversation in the prompt

mem0 is the only entry with a per-category breakdown; we trail it everywhere, most on multi-hop (−6.7) and open-domain (−11.5), at a third fewer prompt tokens with a much smaller answerer. Swapping the answerer moves a score more than swapping the memory system, so treat the ordering as noise.

Two findings cut against us and are published anyway: the knowledge graph does not beat plain chunk retrieval on LoCoMo (paired McNemar p = 1.00) and costs 77% more tokens, and a larger retrieval budget does not lift the score. LoCoMo asks needle questions over conversations that fit in a context window; it does not test what a graph is for.

Protocol, full tables and raw rows: benchmarks/. Setup and traps: benchmarks/SETUP.md.

Learn more

Documentation

Site

Inspiration

  • cognee for the memory philosophy: a typed graph, ontology-constrained extraction, deterministic ids, hybrid retrieval, contradictions and supersession as first-class concepts. Where cognee calls a model, Memoose has a skill.

  • OpenWiki for grounded claims: every fact carries a checkable evidence pointer.

  • mem0 for the LoCoMo protocol, with prompts vendored verbatim from memory-benchmarks.

Contributing

Pull requests and issues are welcome; open an issue first for larger changes. uv run pytest runs the suite.

License

Apache 2.0. See LICENSE.

Available Tools

24 tools
add_entity_typeA

Add an entity type when nothing in describe_ontology fits. PascalCase name; optional parent (collapses onto a basic type) and aliases.

Inputs: name (required), description (required), parent, aliases, +1 more.

contradiction_candidatesB

Facts around given entities or relations, grouped by subject, with hotspots where one subject holds several values for one relation. Judge them with the mnemoth-contradictions skill.

Inputs: dataset, entity_names, relation_ids.

cross_connectB

Add relations between existing entities proposed by memify_candidates(cross_connect).

Inputs: relations (required), dataset.

declare_functional_relationsA

Declare relation names that hold a single current value per subject (e.g. current_owner, deployed_in). New assertions then supersede older ones automatically; nothing is deleted.

Inputs: names (required), dataset.

describe_ontologyA

Entity types, functional relations, imported ontologies, and store stats for a dataset. Call once per session before remember.

Inputs: dataset.

forgetA

Forget an entity (and its relations) by exact name, a relation by id, a session, or a whole dataset. Prefer supersede for facts that were true once. Confirm with the user first.

Inputs: entity, dataset, session_id, relation_id, +1 more.

global_contextC

Global context index: one bucket per entity type with its summary, and how many are stale.

Inputs: limit, dataset.

historyA

Provenance ledger for an entity (and its relations) or a relation: every create, merge, assert, supersede, forget with actor and time.

Inputs: limit, entity, dataset, relation_id.

import_ontologyA

Import an OWL/RDF/Turtle ontology (text). Classes become entity types with parents collapsing onto basic types; labels become aliases.

Inputs: text (required), name, format, dataset.

list_datasetsB

List datasets (memory scopes) on this machine; the default for this project and the user-global dataset.

Inputs: no named parameters.

mark_contradictionA

Record that two stored facts cannot both be true. Adds a contradicts edge between their subjects. Use supersede instead when the newer fact simply replaces the older in time.

Inputs: reason (required), first_relation_id (required), second_relation_id (required), dataset, +1 more.

memify_candidatesB

Maintenance proposals: cross_connect (co-occurring entities without a relation), consolidate (near-duplicate names), stale_summaries (global-context buckets needing a summary).

Inputs: kind (required), limit, dataset.

merge_entitiesA

Merge two entities that denote the same thing. Relations and chunks move to keep; drop is removed and recorded as an alias.

Inputs: drop (required), keep (required), dataset.

publish_lessonsB

Persist accepted lessons as Lesson entities linked to what they apply to; marks the session distilled.

Inputs: lessons (required), dataset, session_id.

recallA

Recall memory. Routes the query to a mode unless given: hybrid (default), facts, neighbourhood, lexical (quoted phrase), summaries, temporal, rules, session. Searches the project dataset then the user dataset. Returns ranked raw entities, facts (with evidence, validity, superseded/contested flags), chunks; you synthesise.

Inputs: query (required), hops, mode, limit, +3 more.

rememberA

Store memory as a typed graph: entities (name, type, description) and relations (source --name--> target, one-sentence description, evidence, optional valid_from/valid_to). Pass source_text and a summary so recall can find it lexically. Validates against the ontology, merges entities by name, supersedes functional relations, records provenance, and warns about hotspots that may be contradictions.

Inputs: entities (required), source, dataset, summary, +3 more.

session_add_turnC

Append a turn (user/assistant/tool/system) to the session's fast cache.

Inputs: role (required), text (required), session_id (required), dataset.

session_endC

Close a session. Tells you whether it still needs distillation.

Inputs: session_id (required), dataset.

session_getB

Read a session: turns and context entries, optionally filtered by section.

Inputs: session_id (required), dataset, sections, include_turns.

session_set_contextC

Record a session context entry: goals, rules, preferences, lessons_learned, tool_rules, workflow_state, success_patterns, failure_lessons, environment_facts, or feedback ('+Name'/'-Name' adjusts recall weight). Pass retire_entry_id to replace an outdated entry.

Inputs: content (required), section (required), session_id (required), dataset, +2 more.

session_startB

Start (or resume) a session. Returns standing context (goals, rules, preferences, lessons) to load before work.

Inputs: dataset, session_id.

session_timelineC

Pack a session into batches for distillation, with prior lessons and the curator/writer rules. Then judge and call publish_lessons.

Inputs: session_id (required), dataset, batch_chars.

set_bucket_summaryA

Write the summary for a global-context bucket returned by memify_candidates(stale_summaries).

Inputs: summary (required), bucket_id (required), dataset.

supersedeA

Mark an older fact as superseded by a newer one. The old fact stays in history and leaves default recall.

Inputs: reason (required), new_relation_id (required), old_relation_id (required), dataset.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.3/5.0

    Scored across 24 tools

    Disambiguation5/5

    Each tool targets a distinct operation or resource: recall searches, history traces provenance, remember writes, supersede/mark_contradiction/forget handle different lifecycle actions, and the session_* tools are clearly separated. Even the candidate-generating tools (contradiction_candidates vs memify_candidates) are distinguished by their output and follow-up tools.

    Naming Consistency3/5

    Most tools use snake_case imperative phrases (add_entity_type, merge_entities, set_bucket_summary), but the set mixes in noun-style commands (history, global_context, contradiction_candidates), the session_* prefix sometimes precedes an action (session_get) and sometimes a noun (session_timeline), and memify_candidates is an inconsistent invented form. The overall style is readable, but the conventions are not uniform.

    Tool Count3/5

    24 tools is on the heavy side for a memory server, though the broad domain (ontology, session management, maintenance, provenance) justifies much of it. A few session/maintenance operations could be consolidated without loss of clarity, making the surface feel slightly bloated.

    Completeness4/5

    The core memory lifecycle is well covered: create (remember), read (recall/history/global_context), update (supersede/merge_entities/set_bucket_summary), and delete (forget), plus ontology and session workflows. Minor gaps exist, such as no direct listing of all sessions or entities and no way to create/remove datasets beyond listing/forgetting, but these are workaroundable.

    Maintenance

    ActivitySlowing
    ResponsivenessLimited data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      B
      maintenance
      Provides persistent, graph-based memory for AI agents via MCP, enabling semantic search, wikilink traversal, reminders, and injection protection.
      9
      35
      Apache 2.0
    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables storing and querying a personal knowledge graph as a shared memory, allowing agents and tools to remember facts, entities, relations, and recall relevant context via natural language hybrid search.
      1
      MIT
    • A
      license
      A
      quality
      D
      maintenance
      Provides persistent, multi-tenant knowledge graph memory for MCP-capable AI tools, allowing them to recall and store entities, observations, and relations across sessions with keyword search.
      10
      28 npm
      3
      MIT