Skip to main content

The Sovereign AI Horizontal Memory (SAIHM) Protocol
draft-saihm-memory-protocol-03

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]