01
Whatever arrived becomes a document
A forwarded email, an uploaded PDF, a voice note and a Slack message all leave this stage in the same shape. Everything downstream reads one format.
Memory layer for AI applications
Nothing to file, nothing to tag, nothing to remember to do. This is the whole thing, start to finish.
0things it has read
when does my insurance renew and what am I paying?
1 June, £412, with Aviva.
then, in May
switched to Direct Line in May, £388
Now: £388 with Direct Line, renewing 1 June.
£412 with Aviva
kept, and true until 12 May
The constraint you described on Monday is described again on Thursday. The approach the team abandoned in March is proposed as a fresh idea in August, because the abandoning happened in a pull request comment. The price a supplier quoted is in a photograph on your phone, and the assistant has never seen it.
None of that is a reasoning failure. The model is not wrong; it was never told.
Every increase in context length brings the suggestion that memory is now unnecessary. Resending a year of history on every turn to use four facts from it costs more each month, and models are measurably worse at material buried in the middle of a very long context than at either end.
And a window belongs to one conversation. Whatever its size, the next one starts empty, and so does a different application.
Why models forgetThe pipeline
Four stages. A forwarded email, an uploaded PDF, a voice note and a Slack message all leave the first one in the same shape, carrying the authorisation they came with.
Normalise
Extract
Resolve
Embed
01
A forwarded email, an uploaded PDF, a voice note and a Slack message all leave this stage in the same shape. Everything downstream reads one format.
02
With the entities they mention and the relationships between them. One paragraph may produce several memories, or none — which is why writing returns a job rather than a memory.
03
The same person named three ways becomes one entity. A fact already known is not stored twice. A fact that contradicts a stored one becomes a conflict holding both sides, rather than overwriting it.
04
Separately, and after everything else, so a model change means re-embedding in the background rather than a migration that stops writes.
The whole thing
Six moments, and you are only present for two of them.
It is all written down somewhere. That is the problem.
An insurance letter from March. A doc someone shared. A message in a thread. A date you half remember.
So you connect what you already use. Once, and never again.
This is the part you do. It takes about a minute.
Then months go by, and you do nothing.
Nothing to file, nothing to tag, nothing to remember to do.
And one day you just ask.
In your own words, from wherever you already are.
Then something changes — and the old answer is kept, not lost.
Superseded, with the dates it was true between. Ask what was true in March and it still knows.
Everything you already had, and everything it used to be.
One memory, behind every assistant you connect.
Retrieval, then resolution
One decision over three weeks: considered, decided, implemented, then replaced. Both columns below are handed all four memories. The left one does what a search does and stops; the right one is what this actually assembles and hands to an assistant.
Pick a question
Four memories match, and every one of them is real
Ranked by similarity
Team later moved to another provider.
1:1 with John
Bedrock implementation shipped.
Standup notes
Decided: Amazon Bedrock.
Planning doc
Bedrock raised as an option for model access.
#eng-infra · Slack
A plain search returns
Team later moved to another provider.
1:1 with John · 24 Aug · 0.95
End of result
True, and it does not say what was moved away from, when it was chosen, or that anything shipped on it. The three memories that explain the sentence scored lower and were left behind.
PersistMemory returns
RELEVANT MEMORY
CurrentTeam later moved to another provider.
1:1 with John · valid: 24 Aug — still true
NO LONGER TRUE — these WERE true and have since changed
Bedrock raised as an option for model access.
#eng-infra · Slack · valid: 2 Aug — 10 Aug
Decided: Amazon Bedrock.
Planning doc · valid: 10 Aug — 24 Aug
Bedrock implementation shipped.
Standup notes · valid: 18 Aug — 24 Aug
Kept in the order they happened, so a question about August is still answerable in September. Nothing was overwritten to get here.
And so the assistant answers
Not Bedrock any more. It was chosen on 10 August, shipped on the 18th, and replaced on the 24th.
Retrieval answers the first. The other three are what separate a memory from a search index, and they are the reason the rest of this system exists.
What database are we using?
AWS PostgreSQL, since 14 August.
The current answer, not the loudest match.
What had we originally chosen?
Supabase, from January until August.
Superseded, not overwritten. March is still there.
When did we switch, and why?
14 August. The decision cites connection pooling under load and the cost of a second datastore.
Read from the decision, with its date.
Where did that come from?
A message in the architecture channel, and the meeting the week before.
Every memory carries the source it was extracted from.
Behaviour
Every chat starts from nothing. PersistMemory sits underneath, keeping what matters and handing it back when it is relevant.
Built for the way memory actually behaves
Decisions, tasks, commitments and the people involved — a claim with evidence behind it, and the window it was true for. Search returns the claim, not the paragraph it hid in — a set of claims you can query, not a transcript you have to search.
When two sources disagree, you are told, rather than served whichever ranked higher.
Confidence and importance are kept as a score and as the factors behind it, so something said once in passing is distinguishable from something three sources agree on.
Spaces
A filing rule, an audience and a retention policy — a way of looking at memories you already have. Nothing is moved into one, so the same memory sits in three at once, and correcting it is one correction rather than three.
One memory
CurrentThe vector index runs on pgvector.
#architecture · valid: 14 Aug — still true
Filed in three Spaces · space_memberships
audience: shared · retention: none · rule
The vector index runs on pgvector.
reason: mentions PersistMemory
audience: private · retention: 365 days · inferred
The vector index runs on pgvector.
reason: type: decision
audience: shared · retention: none · explicit
The vector index runs on pgvector.
reason: mentions pgvector
Correcting this memory changes what all three Spaces return, because none of them holds a copy of it.
A collaborator sees the owner’s memories through the Space. Nothing is copied into their account, which is what keeps two hard things simple — revocation, and whose contradiction is whose.
invited_at
With their name on it. An invitation with no author is one nobody can refuse meaningfully.
accepted_at
Null grants nothing. Anyone can put your address on a meeting invite, so being named is not consent — otherwise a stranger could put their material inside your assistant by scheduling a call with you.
revoked_at
Ended, not deleted, so a re-share is visibly a re-share. The memories leave their retrieval on the next query, because nothing was ever copied into their account.
Sight, never ownership. There is no writer and no admin. Every row means one thing — this person may read this Space — because that is the only thing anything honours.
Your record stays yours. Because nothing is copied, their memory never enters your conflict set, so someone else’s reading of a meeting can never supersede a belief you hold. Your assistant can still cite theirs.
In code
First-party SDKs for TypeScript and Python, an HTTP API underneath both, and an MCP server for assistants that would rather do it themselves.
SDK referenceimport { PersistMemory } from "@persistmemory/sdk";
const pm = new PersistMemory({ apiKey: process.env.PM_KEY });
await pm.memories.remember({
text: "We moved the vector index onto pgvector. Priya raised egress cost.",
spaceIds: ["architecture"]
});
const { results } = await pm.search.query({
query: "why did we leave the hosted index"
});You do not have to change how you work. Message it like a person, add it to the assistant you already talk to, or drive it from a terminal. It is the same memory behind all of them.
Message it, like a person
In the assistant you already use
On your own machine
Send it things as they happen — a photo of a letter, a voice note in the car, a line you want to remember. Nothing to install.
Everything Telegram reads, and what it does not →
Telegram is where things go IN. To ask questions, use it from your assistant or the dashboard — the bot confirms what it saved, it does not answer from your memory.
boiler service booked for the 14th, engineer is Tom
Saved.
[photo] insurance renewal letter
Read it — 2 pages. Saved.
/machines
macbook: connected
Connect a WhatsApp Business number and everything sent to it is read into memory — messages, images, documents, voice notes.
This reads a Business number, not your personal chats — no API exists that can read those, and a product claiming otherwise is doing something you would not want.
[document] Q3-invoice-8841.pdf
Read it. £4,120, due 30 September, from Northgate Ltd.
moved the deadline to the 6th
Saved. The earlier date is kept as superseded.
Give ChatGPT a memory that survives the chat. No code, no file to edit — one address pasted into settings.
What the assistant can and cannot do with it →
Needs a ChatGPT plan that allows custom connectors.
General
Personalisation
Connectors
Data controls
Add custom connector
Server address
PersistMemory wants to
Connected
Ask it to remember something. It is there in next week's chat.
The same address, added to Claude on the web or in the desktop app.
Profile
Appearance
Connectors
Privacy
Add custom connector
Server address
PersistMemory wants to
Connected
Claude writes memories as you talk, and reads them back later.
Or, in Claude Code — one line, no settings screen:
# one line, and it is connected
$ claude mcp add --transport http persistmemory https://mcp.persistmemory.com/mcp
Added stdio MCP server persistmemory
# then, inside Claude Code
$ /mcp
persistmemory connected · authenticate to finish
Editors and coding agents that speak MCP read the same memory, so a decision you explained in one is there in the next.
General
Models
MCP
Rules
Add custom connector
Server address
PersistMemory wants to
Connected
The same memory the chat surfaces write to, in your editor.
Or edit the file directly — Codex uses ~/.codex/config.toml:
{
"mcpServers": {
"persistmemory": {
"url": "https://mcp.persistmemory.com/mcp"
}
}
}Capture and search from the shell — and connect this computer, so your assistants can ask it for a file you never uploaded.
$ curl -fsSL https://persistmemory.com/install.sh | sh
installed pm 0.1.0 -> /usr/local/bin/pm
$ pm auth login
Signed in as you@example.com
# capture
$ pm remember "shipped the migration on the 12th"
Remembered.
# and ask for it back
$ pm search "when did the migration ship"
12 March — shipped the migration. high confidence
# let this machine answer for your assistants
$ pm agent --root ~/notes --root ~/projects
Answering as macbook, from: ~/notes, ~/projects Nothing outside those folders can be read.
From a terminal
The CLI signs in through your browser with PKCE, so your password is never typed into a terminal and never passes through it. What comes back is a token scoped to what you approved.
Every other memory tool is somewhere to put things. Ask this one for a file off your own desk and it goes and gets it — after it asks you.
A Telegram message, an assistant, the command line. No terminal required, and nothing to install on the phone.
A request a model made never reads anything on its own. Everything this system ingests — including other people's email — is in the same context that chose the path, so a person approves the exact one.
Into the same chat, as the file itself. Not a link to a dashboard, not a summary of it.
The approval
Nothing ever calls into your machine. pm agent dials out from it, and anything it is asked to do waits on a page only you can reach. What is shown there is the argv itself, derived from the list that will be executed — not a description written beside it, because approving a description is not approving a command.
A connected app (MCP) asked to RUN
$ rg --files-with-matches "quarterly forecast" /Users/priya/Documents
2 minutes ago · expires in 8 minutes
This runs on your computer. Read the whole line — approving it approves exactly that, not a description of it. Your machine still refuses anything that reaches the network or runs a language, whatever you say here.
On your machine
Nothing yet.
It waits, and expires on its own if you never answer. A request arriving is not evidence anybody wanted it — everything this account has taken in, including other people’s email, is read into the same context that decided to ask.
Why the network is never allowed. Private data, untrusted content and a way out is exfiltration. Each is survivable alone; together, no approval dialog catches them, because the person approving cannot see where the bytes go.
Why a language is never allowed. bash -c is not one command, it is every command at once, and so is find -exec. The line you read would not be the line that ran.
Not a second place to write things down. The memory is built from where the work already happens, and a permission attached to a source is carried through rather than reapplied.
Claude, ChatGPT and Cursor, over MCP.
Forward a message, send a voice note or a photo.
Forward anything to your own ingest address.
Ask for a file off your desk. It waits for your yes.
PDFs and scans read for text, not filenames.
Anything else, straight to the API or the CLI.
Documents and their revisions, not just their names.
Channels you connect, with their access rules intact.
Messages and the files shared in them.
Recordings transcribed, with who said what.
One that reasons badly with no memory will reason badly with a good one. Memory makes it consistent with what was actually said, which is a different property from being right.
Your assistant already does that well. Duplicating it would mean a stale second copy of something accurate by definition. This holds what the code cannot say about itself.
Nothing here decides what matters, sets a reminder, or files things into a system. It remembers what it was given and answers questions about it.
Keep your own copies of anything you cannot afford to lose. This is a memory for your assistants, not a system of record.