{
  "markdown": "<!-- mcp-name: io.github.Astrix-Labs/papez -->\n<p align=\"center\">\n  <picture>\n    <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://raw.githubusercontent.com/Astrix-Labs/papez/main/docs/assets/papez-wordmark-dark.svg\">\n    <img alt=\"Papez: your personal memory for AI\" width=\"360\" src=\"https://raw.githubusercontent.com/Astrix-Labs/papez/main/docs/assets/papez-wordmark-light.svg\">\n  </picture>\n</p>\n\n[![PyPI](https://img.shields.io/pypi/v/papez)](https://pypi.org/project/papez/)\n[![PyPI Downloads](https://img.shields.io/pypi/dm/papez)](https://pypi.org/project/papez/)\n[![CI](https://github.com/Astrix-Labs/papez/actions/workflows/ci.yml/badge.svg)](https://github.com/Astrix-Labs/papez/actions/workflows/ci.yml)\n[![License: AGPL v3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)\n\n# Papez\n\n**The intelligence layer for AI memory.**\n\n> Papez doesn't just remember what happened; it remembers why. A scoring engine + causal graph + lifecycle manager for AI agent memory. Speaks MCP natively.\n\n## LoCoMo benchmark (certified)\n\n| System | Score | Protocol |\n|---|---|---|\n| **Papez** | **85.55 ± 0.37** | Frozen: gpt-4o-mini answerer + judge, temp 0, n=1,540, cats 1–4, 10 runs (July 2026) |\n| Zep | 75.14 | Comparable published setup |\n| Mem0 | 66.9 | Comparable published setup (Mem0 paper) |\n\nSelf-reported vendor figures above ~90 use different answerers/judges and are not comparable — the oracle retrieval ceiling under this frozen protocol is 94.9. Reproduce it yourself: [Astrix-Labs/locomo-harness](https://github.com/Astrix-Labs/locomo-harness) · [full methodology](https://papez.ai/developers/methodology) · [per-run results](https://papez.ai/benchmarks/locomo).\n\n**Hosted product:** [papez.ai](https://papez.ai) — your personal memory for AI, carried across ChatGPT, Claude, and every MCP app · [Pricing](https://papez.ai/pricing) · [Developer docs](https://papez.ai/developers) · [Benchmark methodology](https://papez.ai/developers/methodology) (85.55 on LoCoMo, certified over 10 runs, receipts published)\n\n## What is this\n\nPapez is a scoring engine, causal graph, and lifecycle manager for AI memory. Memories are scored by a multiplicative formula (relevance × connectivity × reactivation), connected in a causal graph, and actively forgotten when they become irrelevant.\n\nThis package (`papez`) is the core library: an in-memory causal graph engine with optional JSON persistence, plus a stdio MCP server. It has no database dependency and no REST API. A hosted product built on top of this library — with Postgres, additional storage backends, and a REST/HTTP MCP API — is available separately at `api.papez.ai`; it is not part of this package.\n\n## Why\n\n- **Flat memory doesn't scale.** Dumping everything into a vector store gives you recall with zero understanding. The 500th memory buries the 5 that matter.\n- **No forgetting = no intelligence.** Real memory systems forget. Without active pruning, your AI drowns in stale context.\n- **No causal reasoning.** Vector similarity can't answer \"why did I choose X?\" — you need a graph.\n\nYour AI remembers everything but understands nothing. Papez fixes that.\n\n## Quick Start\n\nRequires Python 3.11 or newer.\n\nInstall the package. The base install has zero database dependencies — state lives in memory and is optionally persisted to a JSON file.\n\n```bash\npip install papez\n```\n\nOptional extras:\n\n```bash\npip install 'papez[openai]'      # OpenAI embeddings\npip install 'papez[local]'       # Local embeddings (sentence-transformers, no API key)\npip install 'papez[anthropic]'   # LLM-based causal inference (consolidation, contradiction detection)\n```\n\nRun the stdio MCP server directly:\n\n```bash\npython3 -m papez\n```\n\n### From source\n\n```bash\ngit clone https://github.com/Astrix-Labs/papez.git\ncd papez\npip install -e '.[dev]'\npytest tests/\n```\n\n## Connect to your AI\n\n### Claude Code\n\n```bash\nclaude mcp add papez -- python -m papez\n```\n\n### Claude Desktop\n\nAdd to your `claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"papez\": {\n      \"command\": \"python\",\n      \"args\": [\"-m\", \"papez\"]\n    }\n  }\n}\n```\n\n### Reliability & retries\n\nThe stdio server is a single local process. Under load — or during a restart or\nredeploy of a hosted transport in front of it — a tool call can transiently fail\nor the connection can briefly go unresponsive. Memory writes and reads are not\nworth crashing an agent turn over, so **clients should degrade gracefully rather\nthan treat a memory call as fatal**:\n\n- **The server degrades gracefully too**: a tool exception (or a missing\n  required argument) is returned as a structured\n  `{\"error\": \"...\", \"retryable\": bool}` payload instead of a protocol-level\n  MCP failure, so a memory hiccup never crashes the transport. The\n  `retryable` flag encodes the guidance below — `true` only for read tools.\n- **Retry idempotent reads** (`memory_recall`, `memory_search`, `memory_traverse`,\n  `memory_explain`, `memory_stats`) with a short bounded backoff (e.g. 2–3\n  attempts). These have no side effects worth worrying about beyond reactivation\n  bookkeeping.\n- **Do not blindly retry `memory_store` / `memory_amend`** on an ambiguous timeout\n  — a silent success followed by a retry creates a duplicate node. Prefer to\n  continue the turn and reconcile on the next `memory_recall`, or pass a stable\n  `source_session` so duplicates are easy to spot.\n- **Treat memory as best-effort context, not a hard dependency.** If a call fails,\n  proceed with whatever context you already have and try again next turn rather\n  than aborting. The graph is durable; a missed write is recoverable, a crashed\n  agent turn is not.\n\n## MCP Tools\n\n| Tool | Description |\n|------|-------------|\n| `memory_store` | Store a new memory. Use `related` for writer-specified **typed** edges (`{id, type}`); `related_to` is legacy and always creates `caused_by`. Optional `category`. May return `possible_conflicts` (heuristic hints). |\n| `memory_amend` | Record a correction: creates a new memory that **supersedes** an existing one. The old memory is kept (decayed in recall), not deleted. |\n| `memory_recall` | Recall memories by natural language query (vector + keyword + graph spreading activation). Supports `verbosity: \"concise\"` for lightweight payloads. |\n| `memory_search` | Filtered vector search by status, category, date (`since`), last-active date (`active_since`), or entity. Pass an **empty query** to enumerate by recency instead (no embedder needed) — with `since`/`active_since` this answers \"what's new since I last looked\" without knowing what to query for. |\n| `memory_traverse` | Walk the causal graph from a node. Returns reachable **nodes and the edges** of the induced subgraph (`source/target/type/weight/created_by`) — a superset of the BFS tree, so paths can be reconstructed. Honors `edge_types`. |\n| `memory_explain` | Explain a memory's score. Includes a `score_model` block (formula + live per-force breakdown + staleness note) and `removal_impact`. |\n| `memory_stats` | Get memory system statistics |\n| `pin_memory` | Pin a memory so it's never forgotten |\n| `unpin_memory` | Unpin a previously pinned memory |\n| `delete_memory` | Permanently delete a memory |\n| `list_core_memories` | List core memories, optionally filtered by category |\n| `set_core_preferences` | Set user preferences for core memory categories |\n| `promote_to_org` | Promote a private memory to org visibility |\n\n### Writer-specified edges & corrections\n\n`memory_store`'s `related` argument lets the writer set edge semantics instead of\nguessing. Each entry is `{\"id\": \"<node-id>\", \"type\": \"<edge-type>\"}`, directed\n`new_node --type--> target` (so `supersedes` means the new node supersedes the\ntarget). Invalid types are rejected **before** the node is created — explicit\nwrites never half-succeed. `related_to` still exists but always creates\n`caused_by`; prefer `related`.\n\nTo correct a fact, use `memory_amend(node_id, content, reason=...)`: it stores the\nnew version, links it `SUPERSEDES → old`, and **keeps the old memory** for audit.\nRecall automatically deprioritizes superseded hits and tags them with\n`superseded_by`.\n\nWhen you `memory_store` something that lexically disagrees with an auto-link\ncandidate (a changed number, a negation), the result may include\n`possible_conflicts` — heuristic hints, **not** verified contradictions, and never\nmaterialized as edges. Use them to decide whether to `memory_amend`.\n\n### Concise recall\n\n`memory_recall(query, verbosity=\"concise\")` skips the causal-chain enrichment and\nreturns only `id / summary / status / score / activation / is_core` (plus\n`superseded_by` when set) per hit — much cheaper on tokens for high-frequency\nlookups. `verbosity=\"full\"` (the default) is unchanged. Reactivation writes still\noccur in both modes (they are governed by `read_only`, not `verbosity`).\n\nSee [`docs/scoring.md`](docs/scoring.md) for what `activation` / `decay_score`\nactually mean — in short, it is a retention weight that **rises** when a memory is\nrecalled, not a countdown to deletion.\n\n## How it works\n\nEvery memory is scored by three forces multiplied together:\n\n```\ndecay_score = relevance × connectivity × reactivation\n```\n\n- **Relevance** decays over time. Old memories fade unless reinforced.\n- **Connectivity** rewards memories with many causal links. Hub memories survive.\n- **Reactivation** boosts memories that keep getting recalled. Frequency matters.\n\nBecause the formula is multiplicative, a memory must score on *all three* axes to survive. A highly connected but never-accessed memory still decays. A frequently recalled but causally orphaned memory still fades.\n\n`decay_score` (aliased `activation` on every hit) is a **retention weight, not a deletion countdown** — recalling a memory *raises* it, and a low score just means \"resting,\" not \"doomed.\" Deletion requires a low score **and** orphaned **and** unpinned **and** non-core **and** non-org **and** idle (not stored, recalled or reactivated for 30 days, `GENESYS_FORGETTING_MIN_IDLE_DAYS`), all at once. The stdio server runs the rescore-transition-prune pass every 10 minutes (`GENESYS_MAINTENANCE_INTERVAL_S`; 0 disables it). See [`docs/scoring.md`](docs/scoring.md) for the full model and worked numbers.\n\n```\nSTORE → ACTIVE → DORMANT → FADING → PRUNED\n           ↑                    │\n           └── reactivation ────┘\n                                  (only if score=0, orphan, not pinned)\n```\n\nMemories can also be promoted to **core** status — structurally important memories that are auto-pinned and never pruned.\n\n## Benchmark Results\n\nSee the [certified LoCoMo results](#locomo-benchmark-certified) at the top of this README: **85.55 ± 0.37** over 10 runs under a frozen protocol (gpt-4o-mini answerer and judge, temperature 0, n=1,540, categories 1–4). Category 5 — adversarial questions with disputed ground truth — is excluded, matching the comparable published setups.\n\nEvery run is reproducible: the harness is at [Astrix-Labs/locomo-harness](https://github.com/Astrix-Labs/locomo-harness), with [full methodology](https://papez.ai/developers/methodology) and [per-run results](https://papez.ai/benchmarks/locomo) published. Reproduction scripts for the in-repo scenarios are in [`benchmarks/`](benchmarks/).\n\n## Storage backend\n\nThis package ships one storage backend: an in-memory causal graph (`storage/memory.py`) with optional JSON persistence via `GENESYS_PERSIST_PATH`. No database is required.\n\nAdditional backends — Postgres/pgvector, FalkorDB, MongoDB, and an Obsidian vault adapter — along with a REST API, OAuth, and multi-user auth, are part of the hosted product at `api.papez.ai` and are not included in this repo.\n\nWant a different storage backend for the open-source library? Implement the provider protocols in [`storage/base.py`](src/papez/storage/base.py) and bring your own.\n\n## Configuration\n\nCopy `.env.example` to `.env` and set:\n\n| Variable | Required | Description |\n|----------|----------|-------------|\n| `OPENAI_API_KEY` | Unless `GENESYS_EMBEDDER=local` | Embeddings |\n| `ANTHROPIC_API_KEY` | No | Enables LLM-based causal inference (consolidation, contradiction detection). Off by default — without it, causal edges only come from edges the caller explicitly declares in `memory_store` plus cosine-similarity linking. |\n| `GENESYS_EMBEDDER` | No | `openai` (default) or `local` (sentence-transformers, no API key) |\n| `GENESYS_PERSIST_PATH` | No | JSON file path to persist state across restarts (in-memory otherwise) |\n| `GENESYS_USER_ID` | No | Default user ID for single-tenant mode |\n\n### Auto-link tuning\n\nAuto-linking connects a newly stored memory to semantically similar existing\nmemories. If it is too permissive you get a \"hairball\" — everything ends up ~2\nhops from everything, which destroys traversal scoping. Three knobs bound it:\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `GENESYS_AUTOLINK_MIN_SIMILARITY` | embedder-recommended | Cosine floor to create an auto-link. Explicit value wins over the embedder default. |\n| `GENESYS_AUTOLINK_MAX_EDGES` | `3` | Max auto-links a single `memory_store` may create. Caps fan-out. |\n| `GENESYS_AUTOLINK_MAX_NODE_DEGREE` | `10` | Max `auto_link` edges any single node may *accumulate* as a target. Fan-out alone still lets a hub gain one edge per store forever; this caps the hub itself. |\n\nThe floor is **embedder-aware**: an auto-link is permanent graph structure, so its\nfloor sits *above* the transient recall floor. When `GENESYS_AUTOLINK_MIN_SIMILARITY`\nis unset, the effective floor is the embedder's recommendation — **0.6 for OpenAI**\n(`text-embedding-3-small`, whose genuine matches cluster ~0.5+) and **0.45 for\nlocal** sentence-transformers (whose genuine matches cluster ~0.2–0.4 but whose\nnoise pairs have been observed at ~0.44, so only near-duplicate content\nauto-links locally). Any unknown embedder falls back to 0.45. Auto-linking also\nde-dupes: if a pair is already connected by *any* edge (e.g. a `user_explicit`\n`caused_by`), no parallel `auto_link related_to` is created.\n\nThe `possible_conflicts` hint on `memory_store` scans with its **own, lower\nfloor** (`GENESYS_CONFLICT_MIN_SIMILARITY`, defaulting to the recall floor) over\na wider window (`GENESYS_CONFLICT_SCAN_K`, default 8) — so tightening the\nauto-link floor never shrinks conflict detection.\n\n### Recall / relevance floors\n\nThe same embedder-aware pattern governs recall filtering:\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `GENESYS_RECALL_MIN_SIMILARITY` | embedder-recommended (OpenAI 0.5 / other 0.2) | Cosine floor below which pure vector hits are dropped from `memory_recall`. Keyword hits bypass it. |\n| `GENESYS_CORE_INJECT_MIN_SIMILARITY` | embedder-recommended (OpenAI 0.45 / other 0.2) | Floor for injecting auto-promoted core memories into recall results. Pinned memories are always injected. |\n\n### Scoring knobs\n\nThe three-force scoring formula and its lifecycle thresholds are all\nenv-configurable (see [`engine/config.py`](src/papez/engine/config.py) and\n[`docs/scoring.md`](docs/scoring.md)): `GENESYS_ACTR_DECAY`,\n`GENESYS_RELEVANCE_VECTOR_WEIGHT`, `GENESYS_RELEVANCE_KEYWORD_WEIGHT`,\n`GENESYS_MIN_CONNECTIVITY`, `GENESYS_FORGETTING_THRESHOLD`, the `GENESYS_DORMANCY_*`\ntransition thresholds, and the `GENESYS_CORE_*` promotion weights.\n\nSee [`.env.example`](.env.example) for all options.\n\n## Built by\n\nPapez is built by [Rishi Meka](https://github.com/rishimeka) at [Astrix Labs](https://astrixlabs.ai). It came out of frustration with re-explaining project context to Claude every session. The goal is the intelligence layer between your LLM and your memory — fully open source.\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\n[AGPL-3.0-or-later](LICENSE)\n\n> **Note:** Papez releases prior to v0.3.6 were documented as Apache 2.0 in error. The LICENSE file has always contained the AGPLv3 text. From v0.3.6 onward, all documentation correctly references AGPL-3.0-or-later with a Contributor License Agreement.\n",
  "bytes": 16077,
  "sha": "619a7c839555c7870c618644e71bfc4bcca9ad9e35914a297d13d2a450c23fe4",
  "repo_slug": "astrix-labs/genesys",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_astrix_labs_genesys_memory_0d3cf027/readme"
}