{
  "markdown": "# Echo Memory\n\nShared memory for AI coding agents. What Claude Code learns, Codex and Cursor can recall\n— in one graph, on your own machine, with every write auditable.\n\nApache 2.0. The server makes no LLM call on the write path, so storing a memory adds no\ninference cost of its own.\n\n## Install\n\nRun it yourself — nothing leaves your machine:\n\n```bash\npipx install echo-mem\necho-memory quickstart\n```\n\nThat starts the database, applies the schema, and prints the `claude mcp add` command\nthat registers it with your tools, filled in with the port it actually used. Docker is the only prerequisite; the Postgres image is published, so\nnothing is compiled.\n\nOr use the hosted service and run no database at all:\n\n```bash\npipx install echo-mem\necho-memory connect <key>          # a key from https://api.echo-mem.com\n```\n\nEither way, restart your client afterwards. An MCP server holds the code and config it\nstarted with.\n\nThen, once per machine, so the agent knows *when* to record and recall rather than only\nthat the tools exist:\n\n```bash\necho-memory install --global\n```\n\n## Why\n\nEvery AI agent starts from zero unless something remembers what happened last time, and\nremembers it well enough and fast enough to still be useful after months or years of\naccumulated history. Most memory tools solve short-term recall with plain vector search\nover stored facts. That degrades as history grows: more candidates, more noise, slower\nretrieval. Echo Memory is built around the read/write algorithm and the data structure\nthat keeps working at long horizons, not just at day one:\n\n- **A temporal, self-consolidating memory graph.** Facts are edges between entities, not\n  flat vector rows. Old, rarely-accessed memory doesn't just accumulate: it gets\n  consolidated into higher-level summaries over time (never deleted, always traceable\n  back to the original), so retrieval cost stays bounded by what's *currently relevant*,\n  not by everything that's *ever* been written. See\n  [`docs/designs/echo-memory-design.md`](docs/designs/echo-memory-design.md#long-horizon-memory-architecture)\n  for the actual mechanism.\n- **Real graph structure, not just similarity.** Multi-hop queries like \"how did we end\n  up here?\", answerable because facts are connected, not just individually embedded.\n- **Causal typing, not just similarity.** Edges can be tagged `caused_by`, `led_to`,\n  `blocked_by`, `contradicts`, set by the agent's own read of the conversation, not\n  inferred statistically. Honest about what's tractable today and what isn't.\n- **Auditable by design.** Every change to memory is logged, with a plain-language reason\n  you can read back (`echo-memory why <fact_id>`). Memory that consolidates and edits\n  itself is only trustworthy if you can see why.\n- **A write path that adds no inference.** Extraction happens in the calling agent, never\n  on the server, so recording a memory makes zero *additional* LLM calls. The work does\n  not vanish - it moves to a model that already has the conversation in context - and the\n  figures below measure the server receiving facts, not the extraction that produced them. Measured locally with\n  `echo-memory benchmark`: **write 15ms median, query 8ms, digest 1ms, $0.00 inference\n  cost per episode.** The tradeoff is explicit and worth stating: the agent must arrive\n  with entities and facts already extracted, which is more work for the caller and the\n  reason the [MCP tool contract](docs/DEVELOPMENT.md) spells the shape out. The\n  comparison that makes this matter is Zep/Graphiti, the closest architectural match\n  (bi-temporal edges, fact invalidation, episode provenance): its own published\n  description of ingestion is that \"every episode triggers multiple LLM calls for\n  extraction, entity resolution, and invalidation\" and that \"write cost scales with\n  volume\". Here it doesn't.\n- **One storage engine, every scale.** Postgres + pgvector + Apache AGE, from a single\n  local agent up to an organization-wide shared graph spanning every agent a business\n  runs. No forced migration later. (The novel work is the memory structure and algorithm\n  running on top of Postgres, not a new database engine; see the design doc for why.)\n- **Any agent, not one vendor's.** The interface is [MCP](https://modelcontextprotocol.io):\n  any MCP-compatible agent can read and write the same memory graph, whether that's a\n  coding assistant, a chatbot, an ops agent, or something built in-house.\n\n## Who this is for\n\n- **A developer running local agents** who wants Claude Code, Cursor, or anything else to\n  stop losing context between sessions and tools.\n- **A team or organization running agentic systems in production** (support bots, DevOps\n  agents, internal tooling) that needs a shared memory layer instead of N disconnected\n  ones, with the tenancy model (below) to keep it scoped correctly per agent, per team, or\n  org-wide.\n\n## Status\n\nEarly and staged. See [`docs/designs/`](docs/designs/) for the full architecture and the\nv1a → v1b build plan. **The validated wedge driving v1a is specifically cross-tool coding\nagent memory** (the founder's own daily pain, real and tested). The broader vision above\nis the target this architecture is built toward, not yet something v1a itself proves. v1a\nproves basic recall works before v1b adds causal typing and multi-hop graph retrieval, and\nbefore v1.1 adds the org-wide tenancy the broader vision depends on.\n\n## Setting it up by hand\n\n`quickstart` is the short way. If you would rather see every step, or you are working on\nEcho Memory itself, [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md) has the long version:\nclone, `docker compose up -d`, `pip install -e \".[dev]\"`, `alembic upgrade head`, and the\n`claude mcp add` line with its environment.\n\n**Wiring a second tool? Give it its own `ECHO_MEMORY_AGENT_ID`.** Cursor should say\n`cursor`, Claude Desktop `claude-desktop`. Memory is shared either way, but a fact records\nwhich tool learned it, and two tools claiming the same id makes cross-tool recall\nimpossible to see afterwards. `echo-memory adopt` wires every MCP client on the machine at\nonce, each with its own id, and shows the diff before writing anything.\n\nScoped to one project instead — a single Claude project, a Cursor workspace, a repo whose\nmemory should not mingle with the rest? `echo-memory install [path]` writes a\nproject-scoped MCP config plus a skill (or, for Cursor, an always-applied rule), committed\nalongside the code.\n\nSee [`docs/INTEGRATIONS.md`](docs/INTEGRATIONS.md) for using Echo Memory from an agent\nthat does not speak MCP — a chatbot, a DevOps agent, or any custom tool-calling loop.\n\n## The graph\n\nMemory is a graph, not a list of notes. Entities are nodes; a fact is an **edge**\nbetween two of them. That is the whole data model, and everything below follows\nfrom it.\n\n![The memory graph](docs/images/graph-overview.png)\n\nThree projects here. `checkout-api`, `mobile-app` and `data-pipeline` were\nrecorded in separate sessions and never told about each other, yet the picture\nalready separates them — because separation is a property of the edges, not a\nlabel anyone applied.\n\n**Clusters come from structure.** Densely connected facts are grouped by label\npropagation over the edges, and each cluster is named after its most-connected\nnode. That is why `data-pipeline` sits apart on the left: nothing it knows\ntouches payments. It is also why `checkout-api` and `mobile-app` share a cluster\ndespite being different codebases — they genuinely do share an idea, and the\ngraph found it rather than being told.\n\n**Components are the stronger claim.** Two nodes in different components have no\npath between them at all, which is the strongest statement this graph can make\nthat two memories are unrelated.\n\n**Projects are a facet, not the structure.** Every fact records the project it\nwas written from, and you can colour by it, but project says *where a fact was\nwritten*, not *what it belongs with*.\n\n### Click a node: everything it takes part in\n\n![A node selected](docs/images/graph-node-selected.png)\n\n`idempotency keys` is the concept that joined those two codebases. The panel\nshows it referenced from **checkout-api twice and mobile-app once**, the three\nfacts it appears in, and how the node itself resolved — each mention matched an\nexisting node by exact name rather than creating a duplicate.\n\nNobody wrote \"these projects are related.\" Two sessions independently recorded a\nfact about idempotency keys, entity resolution matched them to one node, and the\nrelationship exists as a consequence.\n\n### Click a link: why memory believes it\n\n![A fact selected](docs/images/graph-fact-selected.png)\n\nThis is what a knowledge graph gives you that a code map cannot. Selecting the\nedge answers, for that single fact:\n\n| | |\n|---|---|\n| **what** | the sentence, its `relation_type`, and how confidently it was stated |\n| **when** | when it became valid, and when it was superseded if it has been |\n| **who** | which agent wrote it, in which session |\n| **where** | which project it came from |\n| **why** | the audit trail — created, superseded from what to what, and the entity-resolution rationale for the nodes at either end |\n\nA superseded fact is never deleted. It stops being drawn, because the graph no\nlonger asserts that relationship, but it stays reachable from its node and keeps\nits full history. `echo-memory why <fact_id>` prints the same trail in a terminal.\n\n### Seeing your own\n\n```bash\necho-memory dashboard --serve --open\n```\n\nThe images above come from a synthetic dataset (`scripts/demo-seed.py`) rather\nthan a real store, for the obvious reason: a real memory graph is full of\nhostnames, account numbers and client names.\n\n## Architecture\n\n- **Storage:** PostgreSQL with the `pgvector` and Apache AGE extensions\n- **Retrieval:** hybrid vector + full-text search (v1a), with Personalized PageRank via\n  `networkx` added in v1b for multi-hop associative retrieval\n- **Interface:** [Model Context Protocol](https://modelcontextprotocol.io) server:\n  `write_episode`, `query_memory`, `record_recall_save`, `get_audit_log`\n\n## Is the graph in good shape?\n\n```\necho-memory health\n```\n\nA score, what is strong, what needs attention, and what to do about each,\nincluding what recall has cost: how often memory was read, how often a read\nreturned anything, roughly how many tokens were injected, and how many saves\nthose reads produced. Writes were counted from the start; reads were not counted\nat all, so nothing could answer whether recall earns what it costs. It\nexists to be run when you have no question - a store can look healthy by every\nnumber this CLI reports while most of its facts came from a bulk import, the\nlast real write was a week ago, and only one of several wired agents has ever\nwritten anything. `--json` for machine-readable output.\n\nNothing in it is gated. The paid tiers sell hosting and the things that only\nexist when several people share a graph; diagnostics about your own data are not\na thing to withhold from the person whose data it is.\n\n## Contributing\n\nSee [`CONTRIBUTING.md`](CONTRIBUTING.md). Issues and PRs welcome; please read the design\ndocs first so proposals fit the staged build plan. A first pull request is asked to sign\nthe [Contributor License Agreement](CLA.md) — once, in the PR thread.\n\n## License\n\nApache License 2.0. See [`LICENSE`](LICENSE).\n\n<!-- The MCP registry proves you own a PyPI package by finding this line in the\n     package's own description. It has to survive into the built distribution,\n     which is why it lives in the README rather than in a workflow. -->\nmcp-name: io.github.ayushcodes10/echo-mem\n",
  "bytes": 11620,
  "sha": "9db9341a03b3d2c59d5ea609bde82c22884680641744e92d97fbbbddb1a22552",
  "repo_slug": "ayushcodes10/echo-mem",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_ayushcodes10_echo_mem_500bd9f9/readme"
}