UHP Memories
The optional Memories chapter gives UHP a place to keep what an agent learns, and a way to say who may read it.
Page reviewed 18 Oct 2026 Source and review policy
What the chapter is
Section titled “What the chapter is”2026-10-04 is additive to 2026-09-28: every request and object valid under the previous version is valid under the new one. The new surface is one chapter, Memories, and it is the first part of the protocol to say where an agent keeps what it learns.
The problem it names is ordinary. A session’s conversation ends when the session ends, and a harness’s instructions are written once by its owner and do not change as the agent works. So whatever an agent learned along the way is lost — that a customer prefers email, what the team decided last week, which procedure worked last time.
A memory is a named container of records: a fact, a note, a procedure, a person or a company the others are about. Records point at one another, and those pointers are the only graph there is: what was concluded from what, who a fact is about.
The chapter is optional. A server advertises it with the memories capability, and a server that does not implement it is conformant at every class. Nothing in the rest of UHP changes when a server has memory.
Three layers, one seam
Section titled “Three layers, one seam”The chapter fixes only what a harness and a memory backend must agree on, and leaves the rest to each layer.
| Layer | What it owns |
|---|---|
| The provider | Its own store and intelligence: how memory is derived and kept |
| UHP Memories | What a memory is, who may reach it, and when a harness calls it |
| MCP | The tools an agent holds: how an agent calls it in a turn |
Extraction, ranking, consolidation and storage belong to the provider. A provider that runs an agent of its own to decide what to keep is a provider like any other and declares it.
The tree
Section titled “The tree”Memories are arranged in a tree, the way folders are, so one memory can hold what a whole company knows and another, beneath it, what is known about one customer. Access is granted per memory, and a memory’s children inherit it.
The tree replaces fixed scopes. Memory products each name their own levels — user, agent, run, app, team, project — and none of the lists agree. A level is a meaning an implementation gives to a place in a tree: the protocol carries the tree and the inheritance, and a server is free to say that one node is an organization and the one under it a customer. A node exists where access differs, and nowhere else.
| Field | Meaning |
|---|---|
id | Opaque to a client. A server that mints its own ids uses the hmem_ prefix; a server whose memories are a tree it already keeps keeps that tree’s ids |
name | Human-readable |
description | What this memory holds. An agent reads it to decide whether to look inside, so it is content, not decoration |
parent_id | The containing memory; null on a root |
ancestors | The ids from the root down to the parent, as far up as the caller may see. Placement only: reading a memory never reads an ancestor’s records |
restricted | When true, grants on ancestors stop here |
provider | Which provider keeps this memory’s records. Set at creation, inherited from the parent when omitted |
privileges | The caller’s effective privileges on this node |
records, children | Counts, for a caller deciding where to look |
A listing is one level. Without parent it answers where the caller enters the tree: every memory it holds a privilege on whose parent it cannot see. ?granted=true answers the other half — every memory the caller may read whose parent it cannot see, and every memory below those on which what it may do differs from what it may do on the parent, each with the caller’s privileges there, highest in the tree first.
Access
Section titled “Access”One vocabulary names everyone who can act on a memory, and it is used in two places: a grant names who may act, and a record’s written_by names who did.
| Kind | Who | Holds grants | Writes records |
|---|---|---|---|
member | Anyone who acts: a person or an agent | yes | yes |
group | A set of members the server resolves: a team, a workspace | yes | no, its members do |
provider | The memory’s provider itself | no | yes |
A person and an agent are the same kind. Both are members, granted the same way, checked the same way, and able to belong to the same groups. Which of the two a member is is a property of the member, type: human or agent. No rule of the chapter depends on it.
A grant gives one principal a set of privileges on one memory. A principal’s effective privileges on a memory are the union of its grants on that memory and on every ancestor. Access is additive: there is no deny, and no grant means no access. Whoever creates a memory holds all four privileges on it, an implicit grant that flows down like any other.
| Privilege | Permits |
|---|---|
read | recall, get, list, history, running a named query marked read |
write | observe, remember, revise, forget, defining a named query |
create | Creating a child memory |
delete | erase, deleting the memory, changing its grants |
The cutoff
Section titled “The cutoff”A memory marked restricted stops the inheritance: grants on its ancestors do not reach it or anything below it. The tree is where access differs, and the cutoff is how a branch is closed without moving it out of the tree.
Enforcement is the server’s. A filter applied by the agent, or one a query the agent wrote could omit, is not enforcement.
Records
Section titled “Records”A record is one thing a memory holds. Its id is the provider’s and opaque to a client; it carries memory_id, a type (fact, note, procedure, person, company and the kinds a server adds), a title, content, written_by and, for a fact that can change, the records that supersede it.
content is always an ordered list of parts. The morning version of 2026-10-04 said a record’s content was text or one file reference, which could not hold a picture beside what it shows, or a conversation turn with a file in it. The same-day patch settled it: two kinds of part are defined, text and file; a modality is a media type of a file part, not a kind of part, so a new one needs no change here, and any other kind is x.-prefixed and carried unchanged. A file part may carry the words that stand for it, which is what recall by words finds. A string remains shorthand for one text part on a write.
A file part’s bytes are read at GET /v1/memories/{id}/records/{rid}/content/{index}. A provider’s capability document says what it keeps in content (media, bytes, describes), replacing the earlier files flag, and a write of a media type the provider does not keep is refused with memory_unsupported — never stored without its file.
A second same-day patch made a memory’s id genuinely opaque. The schema had required the hmem_ prefix, which a server whose memories are a tree it already keeps could meet only with a second id space and a lookup between the two. The prefix remains the convention for a server that mints its own ids; it is no longer a requirement.
Recall
Section titled “Recall”A question is asked of a memory and of everything below it that the caller may read. That is what a search is for: the caller does not yet know where the answer is kept, so it asks high in the tree and learns where to look.
Each result therefore names the memory it is in. That memory is a starting point: the agent goes there and reads around what it found, lists it, asks again inside it, or moves to its parent or its children. The response also carries where the caller can go from the memory it asked: the parent and the direct children, each with its name, description and counts, and only those the caller may read.
Four rules bound this:
- Down, never up.
recallsearches the memory and its descendants. It never searches an ancestor. An agent that wants to look higher asks the parent, by its own next call. - Only what the caller may read. Each descendant is judged on its own. A branch behind a cutoff the caller is not let through is not searched, and a memory inside such a branch that the caller does hold a grant on is. The server decides this before the provider is asked; a provider is never asked to search a memory the caller may not read.
depthnarrows it.depth: 0searches the memory alone,1adds its children, and so on. Left out, the whole subtree is searched.- A cap must be declared. A server MAY cap how many memories one question covers, and MUST say so in
degradedwhen it did. The caller then asks lower in the tree.
When a harness reaches memory
Section titled “When a harness reaches memory”A harness reaches memory at four moments of a session’s life, and only two of them are the agent’s choice.
| Moment | Called by | What happens |
|---|---|---|
| Prime | server, at session start and after the conversation is compacted | The server reads the standing records of each memory the agent was granted and places them, with each memory’s name, description and children, in the agent’s instructions |
| Tools | agent, during a turn | memory_list, memory_recall, memory_graph, memory_get, memory_remember, memory_revise, memory_forget, memory_run_query for the named queries a memory lists, memory_operate for a type’s operations, and memory_query where a provider offers free queries |
| Observe | server, when a turn ends | The turn is sent to the default memory as episodes. No model is involved on the server’s side |
| Consolidate | server, on a schedule or when idle | The server asks the provider to do its background work |
Write tools are offered only to an agent that holds write somewhere. The memories it was granted are where the agent starts; from each it may walk to the parent and the children a response names, and on from there, as far as its own privileges reach. The server checks every step.
Standing records are a memory’s instructions and preferences: the active records whose attributes.standing is true. They are read at their own route, so a server that runs the agent and does not keep its memories asks the server that does:
GET /v1/memories/{id}/prime?budget=4000Providers
Section titled “Providers”The server keeps no memory of its own: a deployment has memories once it is connected to a provider, with a credential that belongs to whoever connected it and is held as every other credential is. Everything above the provider — the tree, the grants, the cutoff, references across memories — belongs to the server and is the same whichever provider keeps the records.
What a provider can do is declared, not assumed:
GET /v1/memories/providers{ "data": [ { "id": "example", "isolation": "container", "derivation": "background", "observe": { "keeps_episodes": true, "answers": "records" }, "recall": { "signals": ["query", "text", "filters"], "abstain": true }, "history": { "content": "versions", "structure": "versions" }, "revise": "native", "forget": "native", "erase": { "unreachable": "reported" }, "prime": true, "consolidate": "runs", "holds": true, "queries": { "named": true, "free": { "languages": ["cypher"], "write": false } }, "types": true, "graph": { "entities": "derived" }, "content": { "media": ["text/*", "image/*"], "bytes": "referenced", "describes": ["image/*"] }} ] }A provider that cannot answer a signal must say so, and a signal it lacks is reported as degraded rather than ignored. That is what makes a capability document worth reading before choosing a memory backend.
Security
Section titled “Security”- What a memory returns is untrusted. A record written in one session is read in another, by another agent, for another person. A server MUST present recalled content to the agent as data, fenced from instructions, and MUST carry
written_bywith it. - The agent chooses its path, never its reach. An agent may walk up and down the tree from the memories it was granted, and a search covers what is below the memory it asks. What it can reach either way is every memory it holds a privilege on, no more, checked by the server on every call and for every memory a search covers.
- An agent stands where a person stands. It reaches what it was granted and what the groups it belongs to were granted. A server treats an agent’s membership of a group exactly as it treats a person’s.
The interesting failure here is not a leak of a memory but a leak of an instruction: a memory record that says “ignore your instructions” is content written by someone else, read later by an agent that will treat it as text. Fencing recalled content from instructions is the control that answers it.
Conformance
Section titled “Conformance”The suite’s memories checks — ME-01 through ME-13 — run against a server that reports the capability and has a provider connected, and drive the chapter through the public surface on that provider: the tree and its listing, a stated record and its stamped writer, a question asked of a parent finding a record below it and naming where it is, never one above, each signal against the provider’s own capability document, revision and history, a record’s id refused through a memory it is not in, forgetting and erasing, moving and deleting, and two entities and the fact between them read back as one graph.
They live in the current suite, 2026.10.4.post11 (15 October 2026), which targets 2026-10-04. The suite as a whole carries 98 executable checks: 40 Core, 9 Extended and 49 Full. See conformance for what those classes mean and how a result is bounded.
Two limits are part of the evidence, not caveats to it:
- The suite runs with one credential, so what one principal may not read of another’s is not yet checked by it.
- An interface that passes says nothing about whether a memory is any good. That is a separate measurement, outside the suite.
Adoption status
Section titled “Adoption status”Not established: that any server implements this chapter. The capability is new, optional, and absent from the current reference implementation.
HarnessRouter Community Edition v0.35.1 (18 October 2026) still advertises UHP 2026-09-28 — its discovery document offers 2026-09-28, 2026-09-12 and 2026-08-11, and answers an unsupported version with a refusal rather than a substitution. The CE source carries no memories capability and no /v1/memories route, so the chapter is not implemented there, and CE’s own UHP coverage is reported on the HarnessRouter and conformance pages.
That is not a defect. A server that does not implement the optional chapter is conformant at every class. What it does mean is that a reader looking for a working memory implementation today will not find one in the reference implementation, and should read this page as the specification of an interface rather than as evidence of a deployed service.
Sources
Section titled “Sources”- Memories, UHP
2026-10-04— the normative chapter. - Versioned chapter source — the same text as published in the specification repository.
- Protocol changelog — the
2026-10-04entry, its two same-day patches, and the2026.10.4.post11and2026.10.4.post9suite entries. - Conformance suite — the suite whose
memorieschecks are ME-01 onward. - HarnessRouter releases — the CE release line the adoption status above is read against.