Skip to main content
Glama
README.md
# Product Memory

A what/why memory server for coding agents, over MCP. It answers what a
piece of a system *means* and *why it was built that way* — down to the
function level — so an agent (or you) stops re-deriving or re-breaking a
decision someone already made. The current code stays the source of truth
for *how*; this store never tries to replace it.

This repo ships with a small **synthetic demo store** (`memory-store/`) —
two fictional services, `orbitcart` (checkout/payments) and `beacon`
(notification dispatch) — so `pm eval`, the tests, and the MCP tools all run
out of the box without pointing at anyone's real codebase. Point
`projects.yaml` at your own repos to use it for real.

## Get it running — no coding experience needed

**1. Download it.** Pick whichever is easier:
   - If you have Git: open Terminal and run `git clone <this repo's URL>`
   - If you don't: on the GitHub page, click the green **Code** button →
     **Download ZIP**, then unzip it.

**2. Open a terminal inside the folder you just downloaded.**
   - **Mac:** find the folder in Finder, right-click it, choose *New Terminal
     at Folder* (or open Terminal and type `cd ` followed by dragging the
     folder in, then press Enter).
   - **Windows:** open the folder in File Explorer, hold Shift and
     right-click inside it, choose *Open PowerShell window here*.
   - **Linux:** right-click inside the folder in your file manager, choose
     *Open Terminal Here* (varies by desktop).

**3. Run the setup script.**
   - **Mac / Linux:** type `bash setup.sh` and press Enter.
   - **Windows:** type `.\setup.ps1` and press Enter. If it says the script
     is blocked, run `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned`
     once first, then try again.

That's it — it installs everything this project needs (nothing system-wide,
no admin password), builds the included demo, and runs a real search to
prove it works. You'll see something like:

```
✓ Python 3 found (3.13.5)
✓ uv found
✓ Dependencies installed
✓ Demo memory store indexed

Trying a real search against the demo store...
  8.75  [adr/verified] adr-0004-idempotency-keys-generated-client-side
        ADR-0004: idempotency keys are generated client-side, not server-side
```

If Claude Code is already on your machine, the script will offer to connect
Product Memory to it — say yes, restart Claude Code, and it's live for every
project. If not, or if you use a different coding agent, see **MCP tools**
below and point your agent's MCP config at
`uv run --directory <this folder> python -m product_memory.server`.

Once it's running, try:
```bash
uv run pm serve             # a local web page to browse the memory
uv run pm search "your question here"
```

When you're ready to use it for real (not the demo), open `projects.yaml`
and point it at your own repositories instead.

## The two design bets

**Nothing an agent writes is trusted on arrival.** Every fact proposed via
`propose_memory` gets `status: proposed` — never `verified` — until a human
runs `pm review`. Trusting a wrong memory costs more than missing a right
one, so the default is "written," not "true."

**Ranking is measured, not assumed.** `pm eval` scores keyword search (BM25
over SQLite FTS5) against a semantic vector index on a fixed set of real
questions with known answers, and re-checks it on every run rather than
settling it once. Whichever ranks better *this run* is the one that ranks —
in the author's private corpus (1,192 items) that's keyword at 0.785 MRR vs.
0.436 for semantic-only — with the vector index only appended below it as
extra recall, never reordering keyword's result. On this repo's small
12-question demo set, keyword alone already finds all 12 (`pm eval` →
`0.819 MRR, 12/12`); run `pm embed` first if you want the semantic/fusion
rows in the comparison too. See `eval/queries.json` and
`product_memory/evaluate.py`.

## How memory gets populated

Never a full backfill — it would be stale before it finished. Four channels:

| # | Channel | When | What lands |
|---|---------|------|------------|
| 1 | Docs import | once per repo | pointers/summaries of CLAUDE.md, CONVENTIONS.md, planning docs — never forked copies |
| 1b | Doc-tree import | once per large docs tree | bulk import with hard filtering (drops vendored docs, stubs, duplicates, "✅ Fixed!" session reports) |
| 2 | Change-time capture | every finished agent task | agent calls `propose_memory` → lands as `proposed` → promoted with `pm review` |
| 3 | Ask-time backfill | whenever you ask "why does X work like this?" | the agent researches once, answers you, and proposes the answer as a memory |

## Layout

```
memory-store/           canonical store — markdown files in git, one fact each
  _inbox/               agent proposals awaiting human promotion (or auto-approved, see below)
  <project>/<repo>/     verified + promoted items
demo-repos/             tiny stub repos the demo store's code_symbol entries point at
projects.yaml           registry: project -> repos -> disk paths
product_memory/
  models.py             data contracts (MemoryItem, TaskContext, WhyCard, ...)
  store.py              parse/iterate/propose store files
  index.py              SQLite FTS5 build + ranked search (disposable index)
  semantic.py           chunking + vector index, used for recall only
  evaluate.py           `pm eval` — MRR per retrieval mode, the ranking gate
  conventions.py        derive a repo's house style (declared + observed)
  retrieval.py          packet assembly (deterministic, no LLM)
  staleness.py           flags memories whose source code/doc changed since
  server.py             FastMCP stdio server — the MCP tools
  webapp.py             FastAPI local server (`pm serve`), loopback only
  dashboard.py          the review queue UI
  ingest/                importers + secret redaction
  cli.py                `pm` — the commands below
eval/queries.json       retrieval cases with known answers
tests/
```

## Commands

```bash
pm serve                 # live local server: real search, feedback, persisted marks
pm dashboard --open      # generate the standalone review-queue file
pm search "query"        # ranked search from the terminal
pm eval                  # score retrieval against eval/queries.json — run before ranking changes
pm conventions --project beacon --repo beacon   # derive a repo's house style
pm review                # the only path from proposed to verified
pm index && pm embed     # rebuild the keyword index and the chunked vector index
pm stale                 # notes whose source moved on
```

## MCP tools

`get_task_context` · `search_product_memory` · `get_project_overview` ·
`get_domain_rules` · `get_related_decisions` · `why_code(file, symbol)` ·
`get_recent_work` · `propose_memory` (writes `proposed`, or auto-approves with
redaction — see `PM_REVIEW=1` to force quarantine instead)

## Setup

New to this and just want it running? Use `bash setup.sh` (`.\setup.ps1` on
Windows) instead — see **Get it running** above. The manual steps below are
the same thing, spelled out:

```bash
git clone <this repo>
cd product-memory
uv sync
uv run pytest
uv run python -m product_memory.cli eval   # or: pm eval, once installed

# register for ALL repos (user scope):
claude mcp add --scope user product-memory -- \
  uv run --directory "$PWD" python -m product_memory.server
```

Then point `projects.yaml` at your own repositories, delete or keep the demo
`orbitcart`/`beacon` entries, and start capturing real memories with
`propose_memory` as you work.

## Secrets

Anything written into the store is passed through `redact_secrets` — a
known-literals list (`secret-literals.txt`, gitignored, or `PM_SECRET_LITERALS`)
plus a generic credential-shape heuristic (label + high-entropy value in
proximity). The demo store ships with nothing to redact; `pm eval`'s test
suite includes a CI guard (`test_demo_store_is_clean`) asserting exactly that.

## License

MIT — see [LICENSE](LICENSE).

TDQS

A3.7/5.0

Scored across 9 tools

Disambiguation4/5

The tools have mostly clear, distinct purposes: search vs. read, context retrieval vs. rule retrieval, and write vs. read. However, the context-retrieval tools (get_project_overview, get_task_context, get_domain_rules, get_related_decisions) overlap somewhat and rely on descriptions to tell them apart, and search_product_memory with full=True partially duplicates read_memory.

Naming Consistency4/5

Most tools follow a consistent get_/search_/read_/propose_ verb pattern, which makes the set predictable. why_code breaks the pattern as a noun-style tool name, and the mix of get_ with search_/read_ is a minor deviation.

Tool Count5/5

Nine tools is well within the ideal range for a product memory server, and each tool covers a distinct retrieval or write need. The count feels appropriately scoped without being bloated or thin.

Completeness4/5

The surface covers the core lifecycle well: search, read, targeted context retrieval, recent work, and recording new memories. There is no explicit update/delete/invalidation tool for memories, though the append-only/id-suffix design suggests this may be intentional; still, explicit correction would make it more complete.