A typed memory primitive for agentic PM work — durable context that survives across runs, sessions, and people, with explicit stores, encoders, and retrievers.
This repo implements the Memory rung of The PM Scaffold — a framework for product management work in the agentic era. See the framework repo for the four-rung thesis and roadmap.
Most PM "memory" today is human memory. That doesn't scale. As soon as an agent enters the workflow, every decision a human made implicitly has to be made explicit, captured, and made accessible to the agent on its next run — or the agent re-derives the wrong answer every time.
The Memory rung is the load-bearing infrastructure for trustworthy agentic PM work. It's also where teams quietly accumulate or lose institutional advantage: organizations that build durable, queryable context stores can deploy more capable agents over time; organizations that don't keep restarting from zero.
pm-memory is the abstract primitive for that work — the typed contract that says "this is what a piece of memory is, this is where it lives, this is how an agent fetches it."
- Memory is typed. Every entry carries content, timestamp, source, tags, and schema version. Untyped memory rots fast; typed memory ages well.
- Store, encoder, retriever are separate. The same memory store can power multiple retrievers; the same retriever can run against multiple stores. Mixing them is a v1.x choice, not a baked-in coupling.
- Provider-agnostic at the store layer. Markdown files, JSON files, SQLite, vector DBs — all valid stores. Pick what fits the use case, not what fits the framework.
- Staleness is a first-class concept. Every entry has a "last touched" timestamp and an optional decay policy. Memory that's allowed to age silently is worse than no memory at all.
flowchart LR
R[Raw input<br/>chat, notes, decisions] --> E[Encoder]
E --> M[MemoryEntry<br/>typed]
M --> S[Store<br/>markdown / json / vector]
S --> Q[Retriever]
Q --> A[Agent / human<br/>asking a question]
| Primitive | What it does |
|---|---|
| MemoryEntry | The typed atom: content + timestamp + source + tags + schema |
| Store | Where entries persist. Pluggable — markdown for human-readable, JSON for structured, vector for semantic |
| Encoder | Turns raw inputs (a chat session, a decision, a captured accomplishment) into well-formed MemoryEntries |
| Retriever | The query interface — fetches relevant entries by tag, date range, semantic similarity, or schema match |
The rung's defining claim: memory is infrastructure, not a feature. Treat it as a side effect of "log it somewhere" and it rots. Treat it as a contract with named layers and it compounds.
The simplest possible Memory rung implementation is already running in production: a master resume skill that captures career accomplishments as they happen, stores them as structured bullets in a single markdown file, and exposes them for retrieval (filtering, polish, tailored-resume extraction).
See examples/master_resume_pattern.md for the extraction — how that domain-specific skill maps onto pm-memory's primitives:
- MemoryEntry = one accomplishment bullet with role, date, scope, impact, metric
- Store = MarkdownStore backed by
master_resume.md - Encoder = the structured-intake conversation that turns "I shipped X this week" into a tight bullet
- Retriever = section lookup, date filtering, or "give me everything for this JD" extraction
That skill has been running for months. Generalizing it into pm-memory is the extraction.
from pm_memory import Memory
from pm_memory.stores import MarkdownStore
memory = Memory(store=MarkdownStore("notes/decisions.md"))
# Capture
memory.add(
content="Decided to ship the v2 cover letter template before broadening the job pipeline.",
source="strategy-session",
tags=["decisions", "job-hunt", "Q2-2026"],
)
# Retrieve by tag
recent_decisions = memory.search(tags=["decisions"], since="2026-05-01")
# Retrieve by semantic similarity (v0.3+ with vector store)
related = memory.search(like="how should I structure cover letters?", top_k=5)The API is intentionally narrow: add, search, update, forget. No god-objects, no clever abstractions hiding behind methods named "magic." Memory is plain.
pip install pm-memory # once published
git clone https://github.com/nich9000/pm-memory
cd pm-memory
pip install -e ".[markdown]"v0 — skeleton with thesis, interfaces, extraction story. Core implementation (working MarkdownStore, basic Retriever, schema validation) is being built across the next iterations.
- v0 — skeleton + interfaces (this commit)
- v0.1 — Working MarkdownStore and JsonStore with basic add/search/update/forget
- v0.2 — Encoder library (markdown bullet, decision log, accomplishment, free-form note)
- v0.3 — Vector store for semantic retrieval (FAISS / Chroma / SQLite-VSS adapter)
- v0.4 — Decay policies and staleness signals
- v0.5 — Cross-rung integration with
pm-orchestration(pipelines that read and write memory between worker steps) - v1.0 — Stable schema, full primitive library
The Memory rung is the rung that gives the other three durable state across runs:
- Specs: Spec drafts and rationale can be stored as memory, retrieved later to inform new specs.
- Orchestration:
pm-orchestrationpipelines can read from memory at the start of a run and write to memory at the end — enabling stateful multi-session workflows. - Evaluation:
pm-evalgrade results can be stored as memory, building a longitudinal quality record per rubric.
MIT.