Skip to content

Documentation

Everything it does, and what it refuses to do.

PersistMemory captures material from the places you already work, extracts what it meant, and hands it back months later. Three ways in: connect a source, point an assistant at the MCP server, or call the API yourself.

What happens between handing something over and being able to search it.

Four stages, all of them asynchronous. Knowing the order is what makes the timing of the API make sense.

  1. 01

    Something arrives

    A connector lists what changed, fetches it, and hands the bytes to the pipeline. A PDF from Drive and a PDF attached to an email take the same path from there.

  2. 02

    It is read, not stored

    The text is normalized, then a model extracts candidate claims from it: decisions, tasks, commitments, preferences, facts, and the people involved.

  3. 03

    It meets what you already know

    Entity resolution, deduplication and conflict detection run against the existing store. One piece of material may produce one memory, several, or none.

  4. 04

    It keeps its history

    A memory that changes is revised into a new version and the old one is superseded, not overwritten. Search hides superseded facts by default, because a stale answer presented as current is the worst thing retrieval can do.

Three things that surprise people

remember does not return a memory

It answers 202 with a job id. Extraction and consolidation run afterwards, so nothing is searchable the instant the call returns. Poll the job if you need to know when; the terminal success state is completed.

Search degrades rather than fails

With embeddings unavailable it falls back to deterministic retrieval and still answers. Read diagnostics.degraded before telling a user the system knows nothing. It may merely be looking with one eye.

Conflicts are surfaced, not settled

When two memories contradict each other and nothing in the evidence decides it, the pair is held for you. A resolution you record outranks everything the system inferred.

One credential, and it is shown once.

Every request carries a bearer token: a pm_live_ key or a session JWT. Keys are minted only while you are signed in on the website, because a key that can mint another key makes revoking the first one pointless.

The response to a mint is the only place the key ever appears. Only its hash is stored, so a client that does not capture it there has lost it.

SDK reference
# Mint a key. Session only, so this runs from the browser,
# not from a script holding another key.
POST /keys
{ "name": "laptop", "scopes": ["read", "write"], "expiresInDays": 90 }

# Then every call carries it.
GET /api/v1/memories?type=decision&limit=50
Authorization: Bearer pm_live_...

# /v1 is the same router, kept for clients that predate the prefix.
GET /v1/memories

Connect a source, or let an assistant do the writing.