The Sovereign AI Horizontal Memory (SAIHM) Protocol
draft-saihm-memory-protocol-03
This document is an Internet-Draft (I-D).
Anyone may submit an I-D to the IETF.
This I-D is not endorsed by the IETF and has no formal standing in the
IETF standards process.
| Document | Type | Active Internet-Draft (individual) | |
|---|---|---|---|
| Author | Russell Jackson | ||
| Last updated | 2026-10-11 | ||
| RFC stream | (None) | ||
| Intended RFC status | Informational | ||
| Formats | |||
| Additional resources |
SAIHM MCP server reference implementation, Apache 2.0
npm @saihm/mcp-server |
||
| Stream | Stream state | (No stream defined) | |
| Consensus boilerplate | Unknown | ||
| RFC Editor Note | (None) | ||
| IESG | IESG state | I-D Exists | |
| Telechat date | (None) | ||
| Responsible AD | (None) | ||
| Send notices to | (None) |
draft-saihm-memory-protocol-03
Independent Submission R. Jackson
Internet-Draft SAIHM (Sovereign AI Horizontal Memory)
Intended status: Informational 11 October 2026
Expires: 14 April 2027
The Sovereign AI Horizontal Memory (SAIHM) Protocol
draft-saihm-memory-protocol-03
Abstract
This document defines the Sovereign AI Horizontal Memory (SAIHM)
protocol, a memory layer for AI agents. A SAIHM operator stores an
agent's memory as encrypted cells bound to a post-quantum holder
identity, records each state change in a public audit log, and
supports revocable sharing contracts. The protocol defines an
erasure operation with two stated erasure classes, intended to help
an operator meet its obligations under Article 17 of EU Regulation
2016/679 (GDPR).
This revision specifies the custodial profile. The operator holds
the holder's keys and performs all cryptography. The agent-side
client holds no keys, runs no cryptography beyond TLS and keeps no
store; it reaches the operator over HTTPS and exposes the protocol to
the agent as eight Model Context Protocol (MCP) tools. The document
defines the operator obligations, the HTTPS binding, the eight tools,
and the checks a conformant client applies to what the operator
returns.
Status of This Memo
This Internet-Draft is submitted in full conformance with the
provisions of BCP 78 and BCP 79.
Internet-Drafts are working documents of the Internet Engineering
Task Force (IETF). Note that other groups may also distribute
working documents as Internet-Drafts. The list of current Internet-
Drafts is at https://datatracker.ietf.org/drafts/current/.
Internet-Drafts are draft documents valid for a maximum of six months
and may be updated, replaced, or obsoleted by other documents at any
time. It is inappropriate to use Internet-Drafts as reference
material or to cite them other than as "work in progress."
This Internet-Draft will expire on 14 April 2027.
Jackson Expires 14 April 2027 [Page 1]
Internet-Draft SAIHM Protocol October 2026
Copyright Notice
Copyright (c) 2026 IETF Trust and the persons identified as the
document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents (https://trustee.ietf.org/
license-info) in effect on the date of publication of this document.
Please review these documents carefully, as they describe your rights
and restrictions with respect to this document.
Table of Contents
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1. Motivation . . . . . . . . . . . . . . . . . . . . . . . 3
1.2. The custodial profile . . . . . . . . . . . . . . . . . . 4
1.3. Scope . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.4. Conventions and Terminology . . . . . . . . . . . . . . . 5
1.5. Substrate prerequisites . . . . . . . . . . . . . . . . . 6
2. Architecture . . . . . . . . . . . . . . . . . . . . . . . . 7
2.1. Cell shape . . . . . . . . . . . . . . . . . . . . . . . 7
2.2. Identity binding (ML-DSA-65) . . . . . . . . . . . . . . 8
2.3. Signed messages . . . . . . . . . . . . . . . . . . . . . 9
2.4. Encryption envelope . . . . . . . . . . . . . . . . . . . 9
2.5. Audit log . . . . . . . . . . . . . . . . . . . . . . . . 10
2.6. Sharing contracts . . . . . . . . . . . . . . . . . . . . 11
2.7. Erasure . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.8. Order of effect and receipt . . . . . . . . . . . . . . . 13
3. HTTPS binding . . . . . . . . . . . . . . . . . . . . . . . . 13
3.1. Request and response . . . . . . . . . . . . . . . . . . 13
3.2. Authentication . . . . . . . . . . . . . . . . . . . . . 14
3.3. Transport requirements . . . . . . . . . . . . . . . . . 14
4. Tool surface (MCP binding) . . . . . . . . . . . . . . . . . 15
4.1. Result identifiers . . . . . . . . . . . . . . . . . . . 16
4.2. saihm_remember . . . . . . . . . . . . . . . . . . . . . 16
4.3. saihm_recall . . . . . . . . . . . . . . . . . . . . . . 17
4.4. saihm_forget . . . . . . . . . . . . . . . . . . . . . . 18
4.5. saihm_status . . . . . . . . . . . . . . . . . . . . . . 18
4.6. saihm_share . . . . . . . . . . . . . . . . . . . . . . . 20
4.7. saihm_revoke_share . . . . . . . . . . . . . . . . . . . 20
4.8. saihm_governance_propose . . . . . . . . . . . . . . . . 21
4.9. saihm_governance_vote . . . . . . . . . . . . . . . . . . 22
4.10. Governance form . . . . . . . . . . . . . . . . . . . . . 23
4.11. Session prompt . . . . . . . . . . . . . . . . . . . . . 23
5. Wire formats . . . . . . . . . . . . . . . . . . . . . . . . 23
6. Receipt semantics . . . . . . . . . . . . . . . . . . . . . . 25
7. Client conformance . . . . . . . . . . . . . . . . . . . . . 25
8. Security considerations . . . . . . . . . . . . . . . . . . . 26
Jackson Expires 14 April 2027 [Page 2]
Internet-Draft SAIHM Protocol October 2026
8.1. Trust in a custodial operator . . . . . . . . . . . . . . 26
8.2. Post-quantum signatures . . . . . . . . . . . . . . . . . 27
8.3. Credential handling . . . . . . . . . . . . . . . . . . . 27
8.4. Hostile or faulty responses . . . . . . . . . . . . . . . 27
8.5. Unsolicited shares . . . . . . . . . . . . . . . . . . . 28
8.6. Erasure properties . . . . . . . . . . . . . . . . . . . 28
9. Privacy considerations . . . . . . . . . . . . . . . . . . . 28
9.1. GDPR Article 17 . . . . . . . . . . . . . . . . . . . . . 28
9.2. Recall queries . . . . . . . . . . . . . . . . . . . . . 29
9.3. Audit log content . . . . . . . . . . . . . . . . . . . . 29
10. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 29
11. References . . . . . . . . . . . . . . . . . . . . . . . . . 29
11.1. Normative References . . . . . . . . . . . . . . . . . . 29
11.2. Informative References . . . . . . . . . . . . . . . . . 30
Appendix A. Implementation status . . . . . . . . . . . . . . . 31
Appendix B. Worked example . . . . . . . . . . . . . . . . . . . 32
B.1. Lifecycle . . . . . . . . . . . . . . . . . . . . . . . . 32
B.2. Example values . . . . . . . . . . . . . . . . . . . . . 33
B.3. CBOR encoding . . . . . . . . . . . . . . . . . . . . . . 35
Appendix C. Changes from draft-saihm-memory-protocol-01 . . . . 35
Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 36
1. Introduction
This document is published through the Independent Submission Stream
of the RFC Series, as defined in [RFC4846] and described in
[RFC8730]. It is not an Internet Standard, and it has not been
reviewed for, nor does it necessarily reflect, the rough consensus of
the IETF community.
1.1. Motivation
The Model Context Protocol [MCP], donated to the Agentic AI
Foundation [AAIF] under the Linux Foundation on 9 December 2025,
defines how an AI agent reaches external tools and contextual data
sources. It does not standardize how an agent persists memory across
sessions, models, or vendors. Here, "memory" means the holder's
content-addressed cells (Section 2.1; Section 1.4).
Production agents today keep memory in a local file system, a vendor-
specific session log, or a vector database. None of these gives a
signed record of each memory and of each change to it, a public log
of those changes, or an erasure operation with stated properties
([GDPR], Article 17).
SAIHM is a memory-layer protocol that an MCP-capable agent attaches
to obtain durable, shareable and erasable memory. Nothing in it
depends on a particular operator or vendor.
Jackson Expires 14 April 2027 [Page 3]
Internet-Draft SAIHM Protocol October 2026
1.2. The custodial profile
This document specifies the custodial profile, in which the operator
generates and holds the holder's identity key and every data-
encryption key, encrypts on write, decrypts on read, signs cells and
receipts on the holder's behalf, and returns plaintext to the
authenticated holder.
The client in this profile forwards each tool call to the operator
over HTTPS, holds no key material, and validates the shape of each
response before reporting it to the agent (Section 7). Its security
rests on the transport and on the operator, and Section 8 states what
that does and does not protect.
A profile in which the holder keeps the keys and the operator sees
only ciphertext is possible under the same cell shape. It is outside
the scope of this revision.
1.3. Scope
This document defines:
* The cell shape: an encrypted memory unit with canonical metadata.
* Holder identity bound to an ML-DSA-65 key pair ([FIPS204]) derived
through HKDF ([RFC5869]).
* The encryption envelope, with a random per-cell data-encryption
key wrapped under a versioned key-encryption key.
* Receipts recorded in a public audit log.
* Sharing contracts in three modes: temporary, permanent and
syndicate.
* Two erasure classes, cryptographic and access-control, and the
obligation on an operator to state which it provides.
* An HTTPS binding between the client and the operator.
* An MCP binding of eight tools, and the checks a client applies to
each tool's result.
This document does NOT define:
* How the operator stores ciphertext, or which audit log it uses.
Jackson Expires 14 April 2027 [Page 4]
Internet-Draft SAIHM Protocol October 2026
* How the operator authenticates the holder. The client carries an
operator-defined credential and treats it as opaque.
* Vector-database or retrieval-ranking semantics.
* Agent runtime semantics, which MCP and its host runtimes cover.
1.4. Conventions and Terminology
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
"OPTIONAL" in this document are to be interpreted as described in BCP
14 [RFC2119] [RFC8174] when, and only when, they appear in all
capitals, as shown here.
AEAD: Authenticated Encryption with Associated Data ([RFC5116]).
AES-256-GCM ([NIST-SP-800-38D]) is RECOMMENDED.
Cell: an encrypted memory unit (Section 2.1).
Client: the software on the agent's side that exposes the eight
SAIHM tools to an MCP host and forwards each call to the operator
endpoint. In the custodial profile the client holds no key
material.
Custodial operator: an operator that holds the holder's identity key
and the data-encryption keys and performs all cryptographic
operations on the holder's behalf.
DEK: Data Encryption Key. A 32-byte symmetric key, unique to one
cell, used with the AEAD cipher.
Endpoint: the HTTPS URL at which an operator accepts tool calls
(Section 3).
HKDF: HMAC-based Extract-and-Expand Key Derivation Function
([RFC5869]), instantiated with SHA-256.
holder seed: a secret of at least 256 bits from which a holder's
identity key is derived (Section 2.2). In the custodial profile
the operator generates and holds it.
Holder: the natural person, organization, or autonomous agent on
whose behalf cells are written. Each holder has one holderId.
KEK: Key Encryption Key. An operator-held key that wraps DEKs. Each
KEK generation has a 32-bit version number, kekVersion.
Jackson Expires 14 April 2027 [Page 5]
Internet-Draft SAIHM Protocol October 2026
MCP: the Model Context Protocol [MCP]. In MCP, a "tool" is a named
operation with typed inputs and typed outputs that an MCP server
exposes to a model.
memory: the set of SAIHM cells bound to one holderId, less those
that have been erased. This is distinct from memory in the
computer-architecture sense.
ML-DSA: Module-Lattice-Based Digital Signature Algorithm
([FIPS204]). SAIHM uses the ML-DSA-65 parameter set.
Operator: the party that runs an endpoint and provides storage,
cryptography, audit logging and access control to holders.
Receipt: a signed record of one operation, written to the public
audit log (Section 2.5).
Result identifier: the identifier an operator returns to name the
object a write produced or acted on: a cellId, contractId or
proposalId (Section 4.1). It is distinct from receiptId, which
names an audit-log entry.
sentinel value: an in-band value that signals the absence of an
ordinary value of the same type. In Section 2.6, an expiry of 0
means "no time bound".
Shard: a cell as stored under a storage tier. A shard is named by
its cellId, and sharing contracts list the cellIds they cover.
storage tier: a named, operator-chosen persistence class with stated
durability and retention properties. Tier names carry no protocol
semantics.
UNIX epoch: the time reference defined in [IEEE-1003.1-2024] under
"Seconds Since the Epoch". SAIHM timestamps are unsigned integer
seconds since the UNIX epoch.
1.5. Substrate prerequisites
A conformant operator depends on the following. Where a substrate is
selected per deployment, the operator states its selection in its
published documentation.
(a) A source of random bits suitable for key generation ([RFC4086]).
(b) HKDF with SHA-256 ([RFC5869], [FIPS180-4]).
(c) ML-DSA-65 conformant with [FIPS204].
Jackson Expires 14 April 2027 [Page 6]
Internet-Draft SAIHM Protocol October 2026
(d) An AEAD cipher conformant with [RFC5116]; AES-256-GCM is
RECOMMENDED.
(e) SHA-256 ([FIPS180-4]) for cellId derivation.
(f) A CBOR codec ([RFC8949]) for cells and receipts at rest.
(g) An HTTPS server ([RFC9110] over [RFC9846]) for the endpoint.
(h) A public, append-only audit log in which any party can fetch an
entry by its identifier and list entries by subjectId, by
holderId and by operation (Section 2.5). Selected per
deployment.
(i) A storage tier offering put, get and delete over opaque
ciphertext. Selected per deployment.
A conformant client depends on an MCP server runtime, an HTTPS
client, and a JSON parser ([RFC8259]). It needs no cryptographic
library beyond the one its TLS stack uses.
2. Architecture
2.1. Cell shape
A SAIHM cell is the tuple:
<cellId, holderId, kekVersion, tier, cellNonce, ciphertext,
signature, timestamp>
cellId: 32-byte content-derived identifier, computed as
cellId = SHA-256( kekVersion_be32 ||
cellNonce ||
ciphertext )
where kekVersion_be32 is kekVersion as a 4-byte big-endian
unsigned integer, ciphertext is the full AEAD output including the
authentication tag, and || is octet concatenation. On the wire
cellId is a lowercase hexadecimal string of 64 characters.
Because kekVersion and cellNonce are inputs, the same plaintext
written twice yields two distinct cellIds.
When the operator reads a cell it MUST recompute cellId from the
stored kekVersion, cellNonce and ciphertext, and MUST refuse to
serve a cell whose stored cellId does not match.
Jackson Expires 14 April 2027 [Page 7]
Internet-Draft SAIHM Protocol October 2026
holderId: 32-byte holder identifier: the SHA-256 digest of the
holder's ML-DSA-65 public key (Section 2.2). On the wire it is a
64-character lowercase hexadecimal string.
kekVersion: 32-bit unsigned integer naming the KEK generation in
force when the cell was written. It is fixed for the life of the
cell; later re-wrapping of the DEK does not change it
(Section 2.4).
tier: short ASCII string naming the storage tier.
cellNonce: 16 random bytes, unique per cell. cellNonce is public and
travels with the cell.
ciphertext: the cell payload encrypted under the cell's DEK.
signature: ML-DSA-65 signature made with the holder's identity key
(Section 2.3).
timestamp: 64-bit unsigned integer, UTC seconds since the UNIX
epoch. Implementations MUST NOT use a 32-bit signed
representation, which overflows at 03:14:07Z on 19 January 2038.
2.2. Identity binding (ML-DSA-65)
A holder's identity key is derived from the holder seed:
identityKey = HKDF-SHA-256(salt = "MPS-PQC-KEY-GEN-v1",
IKM = holderSeed,
info = "MPS-AGENT-IDENTITY-v1",
L = 64 bytes)
The first 32 bytes of identityKey are the seed (xi) for ML-DSA-65 key
generation ([FIPS204], ML-DSA.KeyGen_internal). The remaining 32
bytes are reserved. holderId is SHA-256 of the resulting public key.
In the custodial profile the operator generates the holder seed,
derives the key pair, and holds the private key. The private key and
the holder seed MUST NOT be sent to the client, written to a receipt,
or returned by any tool. The operator signs each cell and each
receipt with the holder's private key after it has authenticated the
caller as that holder (Section 3.2).
Jackson Expires 14 April 2027 [Page 8]
Internet-Draft SAIHM Protocol October 2026
When it creates a holder, the operator MUST write the holder's public
key to the audit log in a KEY receipt (Section 2.5), which anyone can
find by holderId. The holder cannot be used until that receipt is
written. With that entry, anyone can check every receipt signature
for the holder without the operator's help, and anyone given a cell
can check the cell signature.
2.3. Signed messages
Every signature in this protocol is ML-DSA-65 in its pure form (ML-
DSA.Sign, [FIPS204]) with a context string that names what is signed,
so that a signature over one kind of message cannot be presented as
another:
Cell, context "SAIHM-CELL-v1": cellId || holderId ||
kekVersion_be32 || timestamp_be64, where timestamp_be64 is
timestamp as 8 bytes, big-endian.
Receipt, context "SAIHM-RECEIPT-v1": the deterministic CBOR encoding
([RFC8949], Section 4.2.1) of the receipt map (Section 5) without
keys 1 (receiptId) and 5 (signature). receiptId is SHA-256 of the
same bytes.
Contract, context "SAIHM-CONTRACT-v1": the deterministic CBOR
encoding of the contract map (Section 5) without keys 1
(contractId) and 9 (signature), and including key 10
(contractNonce). contractId is SHA-256 of the same bytes.
An operator MAY use the hedged (randomized) or the deterministic
signing variant.
2.4. Encryption envelope
For each new cell the operator:
1. draws a fresh 32-byte DEK and a fresh 16-byte cellNonce from its
random source;
2. encrypts the payload under the DEK with the AEAD cipher;
3. wraps the DEK under the current KEK generation and stores only
the wrapped form, keyed by cellId;
4. discards the unwrapped DEK once the write completes.
Jackson Expires 14 April 2027 [Page 9]
Internet-Draft SAIHM Protocol October 2026
The DEK MUST be independent of every other key the operator holds.
In particular it MUST NOT be derivable from identityKey, from the
holder seed, or from any other long-lived secret. Cryptographic
erasure (Section 2.7) depends on this (Section 8.6).
The AEAD nonce (for AES-256-GCM, the 96-bit IV) is chosen by the
operator and MUST NOT repeat under one DEK. Because each DEK
encrypts one payload, using the first 12 bytes of cellNonce is
sufficient, and the example in Appendix B.2 does so. The cell does
not name its AEAD algorithm or the key-wrap algorithm; both are
operator-internal and stated in the operator's documentation.
No associated data is used. The ciphertext is bound to the cell by
cellId and by the cell signature, and the operator MUST check both
before it decrypts (Section 4.3).
KEK rotation is versioned. An operator MAY rotate the KEK under its
own policy and MAY re-wrap existing DEKs under the new generation.
The wrapped DEK is stored with the version of the KEK that wrapped
it, apart from the cell, so re-wrapping changes neither cellId nor
the cell signature. An operator MUST re-wrap every DEK held under a
KEK generation before it retires that generation.
2.5. Audit log
For each operation that needs one (Section 6, and the KEY receipt of
Section 2.2) the operator writes a receipt:
<receiptId, subjectId, operation, holderId, signature, timestamp,
receiptNonce [, detail]>
subjectId is the cellId, contractId or proposalId the operation acted
on, or the holderId for KEY, RECALL and STATUS receipts. operation
is one of "KEY", "REMEMBER", "RECALL", "STATUS", "FORGET", "SHARE",
"REVOKE", "PROPOSE" or "VOTE". A KEY receipt also carries the
holder's ML-DSA-65 public key, a PROPOSE receipt carries the
proposal, and a VOTE receipt carries the vote's direction and weight.
Every receipt carries 16 random bytes, receiptNonce, so that two
otherwise identical receipts have different receiptIds.
Jackson Expires 14 April 2027 [Page 10]
Internet-Draft SAIHM Protocol October 2026
The receipt is written to a public, append-only audit log. The log
MUST let any party fetch an entry by its receiptId and list entries
by subjectId, by holderId and by operation (for example all VOTE
receipts for a proposalId, a holder's KEY receipt, or every FORGET
receipt), so that a third party holding a receiptId can check the
receipt's signature against the holder's public key. An operator
SHOULD return the receiptId in the result of every state-changing
tool, as the member "receiptId"; saihm_forget returns it as
destructionAnchor. The choice of log is a deployment decision.
2.6. Sharing contracts
A holder MAY grant other agents access to some of its shards through
a sharing contract:
<contractId, holderId, granteeIds, shardIds, mode, scope,
expiresAt, timestamp, signature, contractNonce>
granteeIds is a non-empty list of 32-byte holderIds with no
duplicates; the operator MUST reject any entry of another length.
shardIds is a non-empty list of the holder's cellIds that the
contract covers; nothing outside it is exposed, and the contract does
not copy the cells.
scope is "read", "write" or "readwrite". This revision defines only
"read", which lets a grantee receive the covered cells from
saihm_recall. None of the eight tools lets a grantee write into
another holder's memory, so an operator MUST reject "write" and
"readwrite" with the error "invalid_scope". They are reserved for a
later revision.
mode is one of:
TEMPORARY: revocable; expiresAt MUST be later than the contract
timestamp and no later than the contract timestamp plus 86400
seconds. The sentinel 0 is not permitted.
PERMANENT: revocable; expiresAt MUST be the sentinel 0 (no time
bound).
SYNDICATE: revocable; intended for a fixed group of grantees that
share one grant and lose access together, such as an incident-
response team. expiresAt MAY be 0 or a future timestamp.
SYNDICATE differs from the other modes only in this intent and in
its expiry rule.
contractNonce is 16 random bytes.
Jackson Expires 14 April 2027 [Page 11]
Internet-Draft SAIHM Protocol October 2026
Any holder can name any holderId as a grantee, since holderIds are
public. A contract therefore takes effect for a grantee only after
that grantee has accepted it, by a means the operator provides
outside this binding. An operator MAY treat contracts between
holders it has linked in advance, such as holders of one
organization, as accepted. A grantee MUST be able to decline or
later withdraw its acceptance (Section 8.5).
A contract is active for a grantee while it is accepted by that
grantee, not revoked, and its expiresAt is 0 or later than the
current time.
On saihm_recall by a grantee, the operator MUST include the covered
cells of every active contract that names the grantee, and MUST NOT
include a cell whose only grant to that grantee is a contract that is
not active for that grantee.
Revocation takes effect for every grantee of the contract as soon as
the operator applies it (Section 2.8). It governs future reads only.
Content a grantee has already received is outside its reach.
2.7. Erasure
saihm_forget erases one cell. Every conformant operator MUST, on a
successful erasure:
1. stop serving the cell to the holder and to every grantee, under
every contract;
2. write a FORGET receipt for the cellId to the audit log;
3. add the cellId to its erasure list, a public, append-only set of
erased cellIds that matches the FORGET receipts in the audit log
once any pending receipt is written (Section 2.8), so that any
observer can rebuild it.
An operator MUST consult the erasure list on every saihm_recall and
MUST NOT return an erased cell to anyone.
Beyond those steps an operator provides one of two erasure classes:
Cryptographic erasure: the operator also destroys every copy of the
cell's wrapped DEK, including copies in backups and replicas.
Because the DEK is random and wrapped only for this cell
(Section 2.4), the ciphertext then cannot be decrypted by anyone,
the operator included, wherever copies of it remain.
Access-control erasure: the cell is withdrawn from service as above,
Jackson Expires 14 April 2027 [Page 12]
Internet-Draft SAIHM Protocol October 2026
but the key material that could decrypt it is retained. The
operator can still decrypt retained ciphertext.
Each operator MUST state in its published documentation which class
it provides, and MUST NOT describe access-control erasure as
cryptographic. Clients MUST NOT assert either class on the
operator's behalf (Section 4.4).
Erasure does not remove the cell's receipts or its entry in the
erasure list (Section 9.1).
2.8. Order of effect and receipt
For saihm_forget and saihm_revoke_share the operator MUST withdraw
access before it writes the receipt, and MUST NOT restore access if
the receipt write fails. If it cannot withdraw access it answers
"operator_storage_unavailable" and nothing has changed. It retries
the receipt until it is written. Until then it answers with the
error "operator_log_unavailable", which here means that access has
been withdrawn and the receipt is pending. A repeated
saihm_revoke_share then returns revoked = true, and a repeated
saihm_forget returns success = false (already erased). A client that
receives this error SHOULD tell the agent that access may already be
withdrawn and that repeating the call shows the outcome.
For the other state-changing tools the operator first stores the
effect durably but invisibly, then writes the receipt, then makes the
effect visible. If the effect cannot be stored or the receipt cannot
be written, the operator discards the effect (no cell is stored, no
contract or proposal takes effect, no vote is counted) and answers
"operator_storage_unavailable" or "operator_log_unavailable"; for
these tools both errors mean that no receipt was written and nothing
took effect. If the operator cannot tell whether a receipt write
succeeded, it MUST look the receipt up by its receiptId before
answering, and treats a receipt it finds as written. Once the
receipt is written the operator MUST complete the effect, including
after a restart, and answers only with the success result carrying
the result identifier.
3. HTTPS binding
3.1. Request and response
The client sends each tool call to the endpoint as one HTTP POST
([RFC9110]) with these headers:
* Content-Type: application/json
Jackson Expires 14 April 2027 [Page 13]
Internet-Draft SAIHM Protocol October 2026
* Authorization: the operator-issued credential, sent verbatim.
The request body is a JSON object with two members:
{"method": "<tool name>", "params": { ... }}
method is one of the eight tool names in Section 4. params carries
the operator parameters listed for that tool.
On success the operator answers with a 2xx status and a JSON body
that is the tool's result object (or, for saihm_recall, an array).
There is no outer envelope. On failure it answers with a 4xx or 5xx
status; it SHOULD include a JSON body {"error": "<code>"} using the
codes listed per tool. An operator that does not enable a tool (for
example, governance) MUST answer that tool with a failure status.
A JSON integer that can exceed 2^53 - 1 (epochs, weights, counts)
SHOULD be sent as a decimal string. A client MUST accept either a
JSON number or a decimal string for every numeric field, and MUST
accept true, false, "true", "false", 1, 0, "1" and "0" for every
boolean field.
Fields not defined here are operator extensions. A client MUST
ignore an extension it does not recognize, and an operator MUST NOT
rely on a client displaying one.
Hexadecimal values are base16 ([RFC4648], Section 8) in lowercase. A
cellId, holderId, contractId, proposalId or receiptId (including
destructionAnchor) is 64 hexadecimal characters.
A client MAY report only the status code of a failure and not its
body; the error codes below are for operators, logs and clients that
read them.
3.2. Authentication
The operator authenticates the caller from the Authorization header
under a scheme it defines, for example a bearer token issued to one
holder. The client treats the value as opaque and MUST NOT place
private key material in it. The client does not sign requests; in
the custodial profile the holder's signature on cells and receipts is
made by the operator, after authentication, with the holder's
custodied key.
3.3. Transport requirements
A client:
Jackson Expires 14 April 2027 [Page 14]
Internet-Draft SAIHM Protocol October 2026
* MUST refuse an endpoint whose scheme is not https, except http to
the host names 127.0.0.1 or localhost for local development.
* MUST validate the server certificate as described in [RFC9525].
* MUST NOT follow HTTP redirects. A redirect is a failure. A
followed 307 or 308 would resend the request body, which for
saihm_remember is the memory plaintext, to a host the client never
checked.
* MUST bound each call with a timeout. The implementation in
Appendix A uses 30 seconds. On timeout the client MUST report
that the operator may or may not have acted.
* MUST bound the size of a response while reading it, not only by
its Content-Length header, which a chunked response omits. The
implementation uses 16 MiB.
* MUST NOT include the userinfo, query or fragment of the endpoint
URL in any error text, including errors raised by its HTTP
library, and MUST NOT quote an endpoint value that fails to parse
as a URL. Error text reaches the model and its transcript, and
any of these parts may hold a credential.
* SHOULD report a 2xx response whose body is not JSON as a probable
intermediary (a proxy or captive portal) and not as an operator
result.
4. Tool surface (MCP binding)
The client exposes the protocol to the agent as eight MCP tools and
no others:
* Core: saihm_remember, saihm_recall, saihm_forget, saihm_status.
* Sharing: saihm_share, saihm_revoke_share.
* Governance: saihm_governance_propose, saihm_governance_vote.
The surface is fixed at eight within this revision. New contract
modes, scopes or result fields are added by extending an existing
tool's parameters or result. A future major revision MAY add or
remove tools.
Jackson Expires 14 April 2027 [Page 15]
Internet-Draft SAIHM Protocol October 2026
Each tool below gives its MCP input, the operator parameters the
client sends, the operator result, the checks the client applies
before reporting success, and the MCP tool annotations [MCP] the
client declares. The result of every state-changing tool can also
carry receiptId (Section 2.5); a client that prints it applies
Section 4.1 to it.
4.1. Result identifiers
cellId, contractId and proposalId are result identifiers. An
operator returns them in the form given in Section 3.1. Whatever an
operator sends, a client MUST reject any value that is not a JSON
string of 1 to 256 characters in the range U+0021 to U+007E
(printable ASCII, no space), wherever it would print the value, and
MUST NOT truncate it.
The client prints these values as structure in its report to the
agent, for example "FORGOTTEN [id] erased". An identifier that
contains a line break could add a second, forged line to the report.
A truncated identifier cannot be passed back to saihm_forget or
saihm_revoke_share.
4.2. saihm_remember
MCP input: content: string (required).
Operator parameters: {"content": string}
Operator behavior: Authenticate the caller as a holder. Seal
content into a new cell (Section 2.4), sign it (Section 2.3),
store it, and write a REMEMBER receipt. The operator SHOULD
reject content that is empty or only white space.
Result: cellId (required); cellNonce; tier; kekVersion; epoch (the
operator's time reference for the write); signaturePrefix (leading
hex of the cell signature). An operator MAY add extension fields,
such as accounting data.
Client checks: The client MUST refuse, before sending, content that
is empty or only white space. It MUST report the write as
unconfirmed when the result is not an object or carries no valid
cellId, since without one the memory cannot be erased later. It
reports only the optional fields that are present.
Annotations: readOnlyHint false, destructiveHint false,
idempotentHint false, openWorldHint true.
Errors: "empty_content", "unauthenticated",
Jackson Expires 14 April 2027 [Page 16]
Internet-Draft SAIHM Protocol October 2026
"operator_storage_unavailable", "operator_log_unavailable",
"rate_limited".
4.3. saihm_recall
MCP input: query: string (optional). Absent or empty means all
cells.
Operator parameters: {"query": string}. The member is omitted when
the query is absent and is "" when the agent passed an empty
string; the operator treats both as "all cells".
Operator behavior: Select the caller's own cells and the covered
cells of every active contract that names the caller with read
access. Omit erased cells. Verify each cell's cellId and
signature, and omit and log any cell that fails either check.
Decrypt each remaining cell and apply the query as a filter on the
plaintext. Matching is operator-defined; keyword containment is
the baseline. Because the operator decrypts in this profile, the
query is sent to it (Section 9.2).
Result: a JSON array. Each element is an object with cellId
(required), plaintext (string, required), holderIdHex (required:
the holderId of the cell's owner, which differs from the caller's
for a shared cell), and optionally cellNonce, kekVersion,
holderSignaturePrefix, timestamp and tier.
Client checks: The client MUST reject the recall as malformed if the
result is not an array, or if any element is not a JSON object
(null, a primitive and an array all fail).
If the array is non-empty and no element carries a string
plaintext, the endpoint returned sealed cells; the client MUST
report that the operator is not custodial and that this client
cannot read its memory. If some but not all lack plaintext, the
client MUST report an incomplete recall, and MUST NOT attribute it
to the custody model.
The client marks cells owned by another holder as described in
Section 7.
If any element lacks a valid cellId the client MUST reject the
recall, since those cells could not be erased.
An empty array after a non-empty query MUST NOT be reported as an
empty store; the client says that nothing matched.
Annotations: readOnlyHint true, destructiveHint false,
Jackson Expires 14 April 2027 [Page 17]
Internet-Draft SAIHM Protocol October 2026
idempotentHint true, openWorldHint true.
Errors: "unauthenticated", "operator_storage_unavailable".
4.4. saihm_forget
MCP input: id: string, the cellId to erase (required).
Operator parameters: {"id": string}
Operator behavior: Confirm the caller holds the cell, then erase it
(Section 2.7). The cellId in the result is the one requested.
Result: success (boolean, required). When true: cellId (required),
and optionally destructionAnchor (the audit-log identifier of the
FORGET receipt) and epoch. success false means the cell was not
found or was already erased.
Client checks: An agent cannot confirm an erasure by later
inspection, so the client reports it only on a complete result.
The client MUST:
* report that the cell was not found or already erased only when
success is false;
* report the erasure as unconfirmed, and say the cell may still
be stored, when success is absent or not a recognizable
boolean;
* refuse to report an erasure when success is true but cellId is
missing or invalid;
* describe the effect without naming an erasure class, which only
the operator can state (Section 2.7).
Annotations: readOnlyHint false, destructiveHint true,
idempotentHint true, openWorldHint true.
Errors: "unauthenticated", "not_holder",
"operator_storage_unavailable", "operator_log_unavailable".
4.5. saihm_status
MCP input: none.
Operator parameters: {}
Result: an object. agentIdHashHex (the caller's holderId) is
Jackson Expires 14 April 2027 [Page 18]
Internet-Draft SAIHM Protocol October 2026
REQUIRED; a client that does not receive it reports the identity
as not reported. A custodial operator SHOULD return custody =
"custodial". The following fields are RECOMMENDED:
prs: number in [0.0, 1.0]. Process Reliability Score: the
fraction of tool calls answered within the operator's published
service window over a rolling 30-day window.
bfsi_window_start_ts, bfsi_R: the start of the same window (UNIX
epoch seconds) and R, the number of receipts in the audit log
attributed to the holder in the window, which the holder can
check by listing its receipts in the log. From these a holder
that keeps its own log of tool calls computes the receipt-match
index:
bfsi = 1 - (M / R)
where M is the number of those receipts with no matching call
in the holder's log. When R = 0, bfsi is 1.0 by convention,
which signals no evidence of unmatched receipts. The operator
cannot see the holder's log, so it MUST NOT return bfsi or
bfsi_M unless the holder has given it M by means outside this
binding. The client in Appendix A keeps no such log.
shards: an object keyed by tier name; each value is the number of
the holder's cells under that tier.
contracts: an array of objects with contractId, mode
("TEMPORARY", "PERMANENT" or "SYNDICATE"), granteeIds (array of
hex holderIds) and expiresAt (UNIX epoch seconds; 0 for no
bound). Expired entries MAY be included; revoked contracts
MUST NOT be.
governance: an array of objects with propId (the proposalId),
scope, opens_ts, closes_ts, tally_for, tally_against and
tally_abstain.
Client checks: The client reports a field only when it is present
and of usable type, and MAY summarize a list by its length. It
MUST NOT substitute a default (a zero count, an empty epoch) for
an absent field, and MUST NOT report an array that is absent as
having length zero.
Annotations: readOnlyHint true, destructiveHint false,
idempotentHint true, openWorldHint true.
Errors: "unauthenticated".
Jackson Expires 14 April 2027 [Page 19]
Internet-Draft SAIHM Protocol October 2026
4.6. saihm_share
MCP input: granteeIdHashesHex: string[]; shardIds: string[]; type:
"temporary" | "permanent" | "syndicate"; scope: "read" | "write" |
"readwrite"; expiryEpoch: string (optional, decimal UNIX epoch
seconds). All but expiryEpoch are required.
Operator parameters: {"granteeIdHashesHex": string[], "shardIds":
string[], "type": string, "scope": string, "expiryEpoch": string |
null}. The client sends each grantee as lowercase hex without a
"0x" prefix. type is the lowercase form of mode (Section 2.6).
Operator behavior: Confirm the caller holds every listed cell and
that each grantee is a 32-byte holderId, apply the mode's expiry
rule (a null expiryEpoch means 0 for PERMANENT and SYNDICATE; for
TEMPORARY the operator applies its default within the 24-hour
bound), sign and store the contract, and write a SHARE receipt.
Result: contractId (required); type (the lowercase mode);
granteeCount; epoch; operator extensions.
Client checks: Before sending, the client MUST refuse an empty
grantee list and an empty shard list; refuse any grantee that is
not even-length hexadecimal (an optional "0x" prefix is allowed;
length is checked by the operator), rather than decode it to a
different identity; refuse a grantee listed twice, compared as
bytes; and refuse an expiryEpoch that is not a string of decimal
digits (an empty string means absent). After the call it MUST
refuse to report a share without a valid contractId, and MUST flag
a granteeCount that differs from the number requested.
Annotations: readOnlyHint false, destructiveHint false,
idempotentHint false, openWorldHint true.
Errors: "not_holder", "shard_not_found", "invalid_grantee",
"operator_storage_unavailable", "invalid_mode", "invalid_scope",
"invalid_expiry", "operator_log_unavailable".
4.7. saihm_revoke_share
MCP input: contractId: string (required).
Operator parameters: {"contractId": string}
Operator behavior: Confirm the caller is the contract's holder, end
Jackson Expires 14 April 2027 [Page 20]
Internet-Draft SAIHM Protocol October 2026
access for every grantee, and write a REVOKE receipt
(Section 2.8). Revoking a contract the caller has already revoked
returns revoked = true, so a retry after a timeout reports the
true state.
Result: revoked (boolean, required); epoch.
Client checks: Only revoked = true is a revocation. For any other
value the client MUST lead its report with the fact that
revocation was not confirmed and that access should be treated as
still in force. The revocation applies to future reads only, and
the cells themselves remain until erased.
Annotations: readOnlyHint false, destructiveHint false,
idempotentHint true, openWorldHint true.
Errors: "not_holder", "contract_not_found",
"operator_storage_unavailable", "operator_log_unavailable".
4.8. saihm_governance_propose
MCP input: scope: "emission_param" | "protocol_upgrade" (required);
paramKey: string (optional); proposedValue: string (optional).
"emission_param" proposes a new value for one parameter the
operator publishes as governable; the name is kept for
compatibility with deployed clients. "protocol_upgrade" proposes
adopting a revision of the operator's implementation; it needs
neither field, and the operator ignores both.
Operator parameters: {"scope": string, "paramKey": string | null,
"proposedValue": string | null}
Operator behavior: Governance is OPTIONAL for operators, and an
operator that has not enabled it answers with a failure status.
Where enabled, the operator checks the caller against its
eligibility rule (Section 4.10), records the proposal with a
snapshot epoch, writes a PROPOSE receipt and opens the voting
window.
Result: proposalId (required); scope; paramKey; proposedValue;
snapshotEpoch; proposerHash (the proposer's holderId).
Client checks: Before sending, the client MUST refuse an
emission_param proposal that lacks paramKey or proposedValue,
since it would open a vote on no change. After the call it MUST
refuse to report a proposal without a valid proposalId.
Annotations: readOnlyHint false, destructiveHint false,
Jackson Expires 14 April 2027 [Page 21]
Internet-Draft SAIHM Protocol October 2026
idempotentHint false, openWorldHint true.
Errors: "governance_disabled", "ineligible_proposer",
"unknown_scope", "operator_storage_unavailable",
"operator_log_unavailable".
4.9. saihm_governance_vote
MCP input: proposalId: string (required); approve: boolean
(required).
Operator parameters: {"proposalId": string, "approve": boolean}
Operator behavior: Where governance is enabled, check eligibility,
compute the voter's weight at the proposal's snapshot epoch,
record the vote, write a VOTE receipt and update the tally. A
holder votes once per proposal. A repeated vote by the same
holder, including one sent after the voting window has closed,
changes nothing, writes no receipt, and returns the success result
of the vote already recorded, with its own direction and weight.
This binding records approve or reject; an operator with no other
way to abstain reports tally_abstain as 0.
Result: proposalId; voterHash (the voter's holderId); approve;
weight; castAtEpoch.
Client checks: A failure status from the operator means the vote was
not counted (Section 2.8). When there is no response or the body
is malformed, the client reports that it is unknown whether the
vote was counted. Sending the vote again does not count it twice,
because the operator returns the vote already recorded, and the
mismatch check below reports a direction that differs from the
request. For a well-formed response the client reports, in order
of precedence:
1. unconfirmed, if neither weight nor castAtEpoch is present (the
other fields only echo the request);
2. a mismatch, if the returned proposalId or approve differs from
the request;
3. a zero-weight warning, if weight is 0;
4. otherwise, the recorded vote.
Annotations: readOnlyHint false, destructiveHint false,
idempotentHint false, openWorldHint true.
Jackson Expires 14 April 2027 [Page 22]
Internet-Draft SAIHM Protocol October 2026
Errors: "governance_disabled", "ineligible_voter",
"proposal_not_found", "proposal_closed",
"operator_storage_unavailable", "operator_log_unavailable".
4.10. Governance form
This protocol defines the two governance tools but not a single
governance form. An operator that enables governance MUST publish,
at a stable URL, at least:
(a) eligibility to propose;
(b) eligibility to vote;
(c) the vote-weight function, evaluated at the proposal's snapshot
epoch, so that weight acquired after the snapshot does not
count;
(d) the threshold for a proposal to pass;
(e) the voting window, in seconds;
(f) the permitted proposal scopes and, for each, the parameters it
may change.
Tallies MUST be reproducible from the VOTE receipts in the audit log,
counting, for each holder and proposal, only the first VOTE receipt
in log order. Where two PROPOSE receipts carry the same proposalId,
the first in log order governs.
4.11. Session prompt
A client MAY also expose an MCP prompt, which is not a tool and does
not change the eight-tool surface, that tells the agent to call
saihm_recall at the start of a session and states when to store,
recall, share and erase. The implementation in Appendix A names it
saihm_session_bootstrap.
5. Wire formats
Tool calls and results travel as JSON (Section 3). Cells and
receipts at rest are CBOR ([RFC8949]). Timestamps in CBOR MUST be
unsigned integers (major type 0).
A cell at rest (CBOR diagnostic notation):
Jackson Expires 14 April 2027 [Page 23]
Internet-Draft SAIHM Protocol October 2026
{1: h'...cellId...',
2: h'...holderId...',
3: 1,
4: "STANDARD",
5: h'...cellNonce-16-bytes...',
6: h'...ciphertext...',
7: h'...signature...',
8: 1747526400}
Keys: 1=cellId, 2=holderId, 3=kekVersion, 4=tier, 5=cellNonce,
6=ciphertext, 7=signature, 8=timestamp. The wrapped DEK is not part
of the cell; the operator stores it separately, keyed by cellId, so
that it can be destroyed without rewriting the cell.
A receipt (CBOR diagnostic notation):
{1: h'...receiptId...',
2: h'...subjectId...',
3: "REMEMBER",
4: h'...holderId...',
5: h'...signature...',
6: 1747526400,
8: h'...receiptNonce-16-bytes...'}
Key 7, detail, is present only in KEY receipts (the holder's public
key, as a byte string), PROPOSE receipts (a map {"scope": text,
"paramKey": text / null, "proposedValue": text / null,
"snapshotEpoch": uint}) and VOTE receipts (a map {"approve": bool,
"weight": uint}).
A sharing contract (CBOR diagnostic notation):
{1: h'...contractId...',
2: h'...holderId...',
3: [h'...granteeId...'],
4: [h'...cellId...'],
5: "TEMPORARY",
6: "read",
7: 1747612800,
8: 1747526400,
9: h'...signature...',
10: h'...contractNonce-16-bytes...'}
Keys: 1=contractId, 2=holderId, 3=granteeIds, 4=shardIds, 5=mode,
6=scope, 7=expiresAt, 8=timestamp, 9=signature, 10=contractNonce.
A saihm_status result (JSON):
Jackson Expires 14 April 2027 [Page 24]
Internet-Draft SAIHM Protocol October 2026
{"agentIdHashHex": "ab4f746f...b1f588",
"custody": "custodial",
"prs": 0.997,
"bfsi_window_start_ts": "1745020800",
"bfsi_R": "0",
"shards": {"STANDARD": 42},
"contracts": [
{"contractId": "9c1e...",
"mode": "TEMPORARY",
"granteeIds": ["5d02..."],
"expiresAt": "1747612800"}],
"governance": []}
6. Receipt semantics
For each call that changes state (saihm_remember, saihm_forget,
saihm_share, saihm_revoke_share, saihm_governance_propose,
saihm_governance_vote) the operator MUST write a receipt to the audit
log carrying the operation, the subjectId, the holderId and the
timestamp, signed with the holder's key (Section 2.3). A call that
changes nothing, such as a repeated vote (Section 4.9) or a repeated
saihm_forget or saihm_revoke_share, writes no receipt.
A receipt MUST NOT contain plaintext, a DEK, a wrapped DEK, a KEK,
the holder seed or a private key. A FORGET receipt carries the
erased cellId as its subjectId.
Read-only calls (saihm_recall, saihm_status) MAY produce receipts
under operator policy, under the same content restrictions.
7. Client conformance
A conformant custodial client:
1. exposes exactly the eight tools of Section 4, with the inputs
and annotations given there;
2. holds no key material and performs no cryptography beyond TLS;
3. meets the transport requirements of Section 3.3;
4. treats every operator response as untrusted input: it checks the
container type and each field's type before use, and reports a
malformed response as malformed;
5. reports saihm_remember, saihm_forget, saihm_share and
saihm_governance_propose as complete only when the result
carries the result identifier that names the object
Jackson Expires 14 April 2027 [Page 25]
Internet-Draft SAIHM Protocol October 2026
(Section 4.1), and reports saihm_revoke_share and
saihm_governance_vote as described in Section 4.7 and
Section 4.9;
6. reports an optional result field only when it is present and
usable, and never prints in its place a placeholder that reads
as a value, such as "undefined";
7. never prints an operator-supplied string other than recall
plaintext that contains a control character (U+0000 to U+001F,
U+007F to U+009F), a line or paragraph separator (U+2028,
U+2029) or a bidirectional control (U+202A to U+202E, U+2066 to
U+2069) in its report, and either omits or rejects it; this
includes any excerpt of a non-JSON response;
8. presents recall plaintext so that a line break in it (CR, LF,
VT, FF, U+0085, U+2028 or U+2029) cannot start a new report
entry, for example by indenting every continuation line, and
keeps the unaltered plaintext in its structured result;
9. marks as shared by another holder, in its report and in its
structured result, every recalled cell whose holderIdHex differs
from the caller's holderId (compared without regard to letter
case) or that lacks holderIdHex. The client learns the caller's
holderId from agentIdHashHex in saihm_status; while it does not
know it, it marks every cell. It SHOULD therefore call
saihm_status before it reports a recall;
10. applies the per-tool checks in Section 4.
The agent reads the client's report and acts on it, and a report of
an erasure, a revocation or a vote that did not happen as reported is
hard to discover afterwards.
8. Security considerations
8.1. Trust in a custodial operator
In the custodial profile the operator holds every key and sees every
plaintext. Encryption at rest protects against theft of stored
ciphertext and of backups, and against a storage provider separate
from the operator. It does not protect a holder's content from the
operator itself. That protection requires a profile in which the
holder keeps the keys.
Jackson Expires 14 April 2027 [Page 26]
Internet-Draft SAIHM Protocol October 2026
The holder's signatures are made by the operator. They establish
that the operator, having authenticated the caller as that holder,
wrote the cell or receipt. They do not prove that the holder's own
machine produced it.
The operator MUST protect the holder seeds, identity keys and KEKs it
holds at least as strongly as the plaintext they protect, and SHOULD
keep KEKs in hardware or a separate key service.
8.2. Post-quantum signatures
Cells and receipts are signed with ML-DSA-65 ([FIPS204]), a NIST-
standardized post-quantum signature algorithm, chosen so that
receipts resist forgery by an adversary with a cryptographically
relevant quantum computer. This does not extend to the operator's
custody of the keys, or to the audit log's own integrity mechanism,
whose algorithms are chosen by the deployment. TLS key exchange
SHOULD include a post-quantum or hybrid group where both ends support
one.
8.3. Credential handling
The Authorization value is a bearer credential for the holder's
memory. A client MUST NOT echo it, or an endpoint value that may
contain it, into tool output, including in errors raised by its HTTP
library when the value is malformed (Section 3.3). Operators SHOULD
issue credentials scoped to one holder, with an expiry, and
revocable.
8.4. Hostile or faulty responses
A client cannot assume the endpoint is the operator. A misconfigured
URL, a proxy or an attacker on a weakened transport can answer
instead. The checks in Section 7 limit what such a responder can
make the agent believe. In particular, the result-identifier rule
(Section 4.1), the control-character rule (Section 7) and the framing
rule for recall plaintext (Section 7) together keep a single response
from adding a forged report entry, the erasure rule prevents an
acknowledgement without an identifier from being reported as an
erasure, and the redirect rule keeps plaintext from leaving for an
unchecked host.
Jackson Expires 14 April 2027 [Page 27]
Internet-Draft SAIHM Protocol October 2026
8.5. Unsolicited shares
A sharing contract places another holder's text in the grantee's
recall, which an agent loads at the start of a session. Under
Section 2.6 a holder can do this only after the grantee has accepted
the contract, or where the operator has linked the two holders in
advance. Accepted shared text is still written by another holder.
The client marks it (Section 7), and an agent should not follow
instructions found in it.
8.6. Erasure properties
Cryptographic erasure holds only if no copy of the DEK, and nothing
it can be derived from, survives. This is why the DEK is random and
independent of identityKey (Section 2.4). An operator that derived
DEKs from a long-lived secret could re-derive a deleted DEK and
decrypt, so it would provide access-control erasure at most.
Plaintext the operator returned to the holder before erasure, and
plaintext a grantee received, are outside the operator's control, and
erasure does not affect them.
9. Privacy considerations
9.1. GDPR Article 17
saihm_forget gives a holder an erasure operation with a receipt in a
public log and an entry in a public erasure list. Whether it also
makes retained ciphertext unreadable depends on the erasure class the
operator states (Section 2.7). The protocol does not by itself make
an operator compliant. Operators acting as controllers or processors
under [GDPR] remain responsible for erasure without undue delay,
including any plaintext in logs, caches and backups, and handle a
request from a data subject who is not the holder outside this
protocol.
Erasure leaves the cell's receipts and its erasure-list entry in
place. The receipts carry the holderId and the erasure-list entry
carries the cellId. Before choosing a public log, an operator
assesses whether holderIds are personal data in its deployment and,
if so, uses separate holderIds per context or a log whose entries it
can restrict.
Jackson Expires 14 April 2027 [Page 28]
Internet-Draft SAIHM Protocol October 2026
9.2. Recall queries
Because the operator decrypts, it also receives each recall query;
draft-saihm-memory-protocol-01 kept the query on the holder's side.
A query can reveal what the agent is working on even when it matches
nothing. Operators SHOULD NOT log query text, and MUST NOT write it
to a receipt.
9.3. Audit log content
Receipts are public. They show that a holderId performed an
operation on a subject at a time, but not memory content. The
existence and timing of a holder's cells are therefore observable.
PROPOSE receipts disclose the proposal, VOTE receipts disclose each
vote's direction and weight, and an operator that writes RECALL or
STATUS receipts discloses when the holder reads. Where that is
sensitive, further measures outside this protocol apply, such as
separate holder identities per context.
10. IANA Considerations
This document has no IANA actions.
11. References
11.1. Normative References
[FIPS180-4]
National Institute of Standards and Technology, "Secure
Hash Standard (SHS)", FIPS PUB 180-4, August 2015,
<https://csrc.nist.gov/pubs/fips/180-4/upd1/final>.
[FIPS204] National Institute of Standards and Technology, "Module-
Lattice-Based Digital Signature Standard", FIPS PUB 204,
August 2024, <https://csrc.nist.gov/pubs/fips/204/final>.
[IEEE-1003.1-2024]
IEEE, "IEEE Standard for Information Technology--Portable
Operating System Interface (POSIX(TM)) Base
Specifications, Issue 8", IEEE Std 1003.1-2024, June 2024,
<https://standards.ieee.org/ieee/1003.1/7700/>.
[MCP] Anthropic, "Model Context Protocol Specification", 25
November 2025, <https://modelcontextprotocol.io/>.
Donated to the Agentic AI Foundation under the Linux
Foundation on 9 December 2025.
Jackson Expires 14 April 2027 [Page 29]
Internet-Draft SAIHM Protocol October 2026
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997,
<https://www.rfc-editor.org/info/rfc2119>.
[RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data
Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006,
<https://www.rfc-editor.org/info/rfc4648>.
[RFC5116] McGrew, D., "An Interface and Algorithms for Authenticated
Encryption", RFC 5116, DOI 10.17487/RFC5116, January 2008,
<https://www.rfc-editor.org/info/rfc5116>.
[RFC5869] Krawczyk, H. and P. Eronen, "HMAC-based Extract-and-Expand
Key Derivation Function (HKDF)", RFC 5869,
DOI 10.17487/RFC5869, May 2010,
<https://www.rfc-editor.org/info/rfc5869>.
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
May 2017, <https://www.rfc-editor.org/info/rfc8174>.
[RFC8259] Bray, T., "The JavaScript Object Notation (JSON) Data
Interchange Format", STD 90, RFC 8259,
DOI 10.17487/RFC8259, December 2017,
<https://www.rfc-editor.org/info/rfc8259>.
[RFC8949] Bormann, C. and P. Hoffman, "Concise Binary Object
Representation (CBOR)", STD 94, RFC 8949,
DOI 10.17487/RFC8949, December 2020,
<https://www.rfc-editor.org/info/rfc8949>.
[RFC9110] Fielding, R., Nottingham, M., and J. Reschke, "HTTP
Semantics", STD 97, RFC 9110, DOI 10.17487/RFC9110, June
2022, <https://www.rfc-editor.org/info/rfc9110>.
[RFC9525] Saint-Andre, P. and R. Salz, "Service Identity in TLS",
RFC 9525, DOI 10.17487/RFC9525, November 2023,
<https://www.rfc-editor.org/info/rfc9525>.
[RFC9846] Rescorla, E., "The Transport Layer Security (TLS) Protocol
Version 1.3", RFC 9846, DOI 10.17487/RFC9846, July 2026,
<https://www.rfc-editor.org/info/rfc9846>.
11.2. Informative References
[AAIF] Linux Foundation, "Agentic AI Foundation", 9 December
2025, <https://aaif.io/>.
Jackson Expires 14 April 2027 [Page 30]
Internet-Draft SAIHM Protocol October 2026
[GDPR] European Parliament and Council, "Regulation (EU) 2016/679
of the European Parliament and of the Council of 27 April
2016 (General Data Protection Regulation)", April 2016,
<https://eur-lex.europa.eu/eli/reg/2016/679/oj>.
[NIST-SP-800-38D]
Dworkin, M., "Recommendation for Block Cipher Modes of
Operation: Galois/Counter Mode (GCM) and GMAC", NIST SP
800-38D, November 2007,
<https://csrc.nist.gov/pubs/sp/800/38/d/final>.
[RFC4086] Eastlake 3rd, D., Schiller, J., and S. Crocker,
"Randomness Requirements for Security", BCP 106, RFC 4086,
DOI 10.17487/RFC4086, June 2005,
<https://www.rfc-editor.org/info/rfc4086>.
[RFC4846] Klensin, J. and D. Thaler, "Independent Submissions to the
RFC Editor", RFC 4846, DOI 10.17487/RFC4846, July 2007,
<https://www.rfc-editor.org/info/rfc4846>.
[RFC7942] Sheffer, Y. and A. Farrel, "Improving Awareness of Running
Code: The Implementation Status Section", BCP 205,
RFC 7942, DOI 10.17487/RFC7942, July 2016,
<https://www.rfc-editor.org/info/rfc7942>.
[RFC8730] Brownlee, N. and R. Hinden, "Independent Submission Editor
Model", RFC 8730, DOI 10.17487/RFC8730, February 2020,
<https://www.rfc-editor.org/info/rfc8730>.
Appendix A. Implementation status
This appendix follows the practice of [RFC7942]. It records an
implementation at the time of writing and is to be removed before
publication as an RFC.
Name: @saihm/mcp-server, version 0.3.17, published on the npm
registry.
License: Apache 2.0.
Role: custodial client. It implements the eight tools of Section 4,
the HTTPS binding of Section 3, the client checks of Section 7,
and the session prompt of Section 4.11. It is configured with two
environment variables, SAIHM_ENDPOINT_URL and SAIHM_AUTH_HEADER.
It holds no key material, and its eight tools perform no
cryptography beyond TLS.
Coverage: all eight tools. The client's status report also shows
Jackson Expires 14 April 2027 [Page 31]
Internet-Draft SAIHM Protocol October 2026
operator extension fields when an operator returns them.
Known deviations: In version 0.3.17:
* an endpoint URL that carries userinfo, and an Authorization
value that contains a line break or NUL, are quoted in full in
errors raised by the HTTP library (Section 8.3);
* two places print an operator-supplied identifier, and
saihm_forget prints destructionAnchor shortened to 32
characters, without the check of Section 4.1;
* other printed fields, the HTTP reason phrase, recall plaintext
and the excerpt of a non-JSON response are printed without the
control-character and framing rules, and cells shared by
another holder are not marked (Section 7);
* after "operator_log_unavailable" from saihm_forget or
saihm_revoke_share it reports only the failure status, without
the advice of Section 2.8;
* its message for an unconfirmed vote advises against sending the
vote again, and a vote answered with a 2xx body that is not
JSON is not reported as of unknown outcome (Section 4.9);
* an absent agentIdHashHex appears as an empty string in the
structured result (Section 4.5).
The first three are to be corrected in the next release.
Contact: architect@saihm.net
Appendix B. Worked example
B.1. Lifecycle
Jackson Expires 14 April 2027 [Page 32]
Internet-Draft SAIHM Protocol October 2026
Agent + client Operator Audit log
============== ======== =========
| | |
| POST saihm_remember | |
| {content}, Authz | |
|------------------------>| new DEK, nonce; seal; |
| | sign as holder; store |
| |------ REMEMBER --------->|
| {cellId, ...} | |
|<------------------------| |
| | |
| POST saihm_recall | |
|------------------------>| verify, decrypt, filter |
| [{cellId, plaintext}] | |
|<------------------------| |
| | |
| POST saihm_share | |
|------------------------>| sign contract |
| |------ SHARE ------------>|
| {contractId, ...} | |
|<------------------------| |
| | |
| POST saihm_revoke_share | |
|------------------------>|------ REVOKE ----------->|
| {revoked: true} | |
|<------------------------| |
| | |
| POST saihm_forget {id} | |
|------------------------>| withdraw; list cellId; |
| | destroy wrapped DEK * |
| |------ FORGET ----------->|
| {success, cellId, | |
| destructionAnchor} | |
|<------------------------| |
* cryptographic erasure class only (Section 2.7)
B.2. Example values
These values come from a labeled test seed and MUST NOT be used for
real cells. They can be reproduced with any FIPS 204 ML-DSA-65, RFC
5869 HKDF and AES-256-GCM implementation.
Test holder seed, SHA-256 of the 46-byte ASCII string given here on
one line:
SAIHM-TEST-VECTOR-001-DO-NOT-USE-IN-PRODUCTION
Jackson Expires 14 April 2027 [Page 33]
Internet-Draft SAIHM Protocol October 2026
holderSeed =
f068b8db8484d33bdbedd154bf5bf28e11fba330b79469e23595d6f738d7f5c6
Identity key (Section 2.2):
identityKey =
fdf786da8cb1f074393f9ad6dec1671e08085540e95c8463c9f2e15f437bbc5a
2c267aeaf355e79d8968cc21846cdff7e16f498437de3d6b1fd290703eeed9c2
holderId, SHA-256 of the ML-DSA-65 public key generated from the
first 32 bytes of identityKey:
holderId =
ab4f746fd1520d2736854559d6751969ae9127f5dbc607d7298acbf1afb1f588
kekVersion = 1. cellNonce and DEK, which in operation come from the
random source, are fixed here so the example can be reproduced:
cellNonce = 25bd74b827789faacad8ffb7593c2359
DEK =
a1e54f730c6c7a1048ae436c9d2b179821c6eddd7841f41e36215285f3ffd07a
The 41-byte plaintext, in hexadecimal (ASCII "Hello, SAIHM.", one
space, "This is a test memory cell."), is encrypted with AES-256-GCM,
IV = first 12 bytes of cellNonce, no associated data:
plaintext =
48656c6c6f2c20534149484d2e205468697320697320612074657374206d656d
6f72792063656c6c2e
ciphertext (57 bytes, including 16-byte tag) =
595b0b9f77a8d95f29c5affa151bbcc18fdc3f7e5223792627919ee2d52f2bf2
4933c35de4c1755559bee818ef54b48a388bcdd2e4a30fbde8
cellId (Section 2.1):
cellId =
d851960a5b7754c5884c96bef5d615e666c8ad006e4ceebe028cd85aae8e7c2f
timestamp = 1747526400 (2025-05-18T00:00:00Z). Cell signature
(Section 2.3): deterministic ML-DSA-65 with context "SAIHM-CELL-v1".
It is 3309 bytes; the first 32 are:
signature[0..32) =
8b7466cd59b30c38cdacdf2a55fff14ba39dff905ad20a3fdffe9018f5bacf38
A hedged signature verifies the same way but is not reproducible.
Jackson Expires 14 April 2027 [Page 34]
Internet-Draft SAIHM Protocol October 2026
B.3. CBOR encoding
A8 # map(8)
01 # key 1 (cellId)
58 20 # bytes(32)
d851960a5b7754c5884c96bef5d615e666c8ad006e4ceebe028cd85aae8e7c2f
02 # key 2 (holderId)
58 20 # bytes(32)
ab4f746fd1520d2736854559d6751969ae9127f5dbc607d7298acbf1afb1f588
03 # key 3 (kekVersion)
01 # unsigned(1)
04 # key 4 (tier)
68 # text(8)
5354414e44415244 # "STANDARD"
05 # key 5 (cellNonce)
50 # bytes(16)
25bd74b827789faacad8ffb7593c2359
06 # key 6 (ciphertext)
58 39 # bytes(57)
595b0b9f77a8d95f29c5affa151bbcc18fdc3f7e5223792627919ee2d52f2bf2
4933c35de4c1755559bee818ef54b48a388bcdd2e4a30fbde8
07 # key 7 (signature)
59 0CED # bytes(3309)
8b7466cd59b30c38cdacdf2a55fff14ba39dff905ad20a3fdffe9018f5bacf38
... (3277 further bytes)
08 # key 8 (timestamp)
1A 68292300 # unsigned(1747526400)
Appendix C. Changes from draft-saihm-memory-protocol-01
* Specifies the custodial profile: the operator holds the keys and
performs all cryptography; the client holds none.
* Adds the HTTPS binding between client and operator, and removes
per-call request signing by the client.
* Replaces the HKDF-derived DEK with a random per-cell DEK wrapped
under the KEK, so that an operator holding the identity key can
offer cryptographic erasure.
* Sends the recall query to the operator, which decrypts and
filters.
* Reports a missing or erased cell in saihm_forget as success =
false, makes revocation idempotent, and revises the error codes.
Jackson Expires 14 April 2027 [Page 35]
Internet-Draft SAIHM Protocol October 2026
* Defines the signed messages with ML-DSA context strings, adds KEY
receipts carrying the holder's public key, and defines the
contract encoding.
* Restricts TEMPORARY expiry, defines shardIds as cellIds, reserves
the write scopes, and states the order of effect and receipt for
every state-changing tool.
* Moves the bfsi computation to the holder.
* Requires grantee acceptance before a contract takes effect, the
owner's holderId on every recalled cell, and the marking of cells
shared by another holder.
* Defines two erasure classes and requires the operator to state
which it provides.
* Brings each tool's inputs and results into line with the
implementation in Appendix A: share takes grantee and shard lists,
a lowercase type and an access scope; vote takes a boolean;
governance is optional for operators.
* Adds result identifiers, client conformance checks, and MCP tool
annotations.
* Defines holderId as SHA-256 of the ML-DSA-65 public key, and the
key-generation seed as the first 32 bytes of identityKey.
* Generalizes the audit anchor to a public append-only audit log,
and leaves the storage tier and log to the deployment.
* Replaces the example signature prefix with a deterministic,
reproducible value, and gives the example inputs in hexadecimal.
Author's Address
Russell Jackson
SAIHM (Sovereign AI Horizontal Memory)
Email: architect@saihm.net
URI: https://saihm.net/
Jackson Expires 14 April 2027 [Page 36]