ERC-8337: Agent Memory State

Hi all,

This is the discussion thread for ERC-8337: Agent Memory State Registry, a draft ERC for verifiable version control of autonomous-agent memory without placing memory content onchain.

Current status

  • Submitted upstream as ERC-8337 in ethereum/ERCs#1910.
  • Awaiting editor review. Live CI status is tracked in the upstream PR.
  • A public Sepolia deployment is live; details are provided below.

Summary

An agent that has been running for a year is not simply the model it started as. It has accumulated preferences, distilled skills, revised policies, and a record of what it did and why.

That accumulated state is rapidly becoming the most valuable part of the agent: it is what users trust, what operators may want to carry to another platform, what may eventually be licensed, and what a counterparty or regulator may ask to audit.

I believe the memory state and behavioral records of future agents need to be preserved. Once an agent becomes an active user of Web3, we don’t know what it did or thought beyond its transactions and identity. Each agent carries three kinds of memory during operation: what it thought at runtime, the reasoning process behind it, and what it thought collectively with other agents. What actions the agent took — and what impact those actions had — need to be recorded as verifiable commitments, selectively disclosable for audit, rather than as public metadata. To be precise about the boundary: the chain never stores or manages the latent-space vectors themselves — it manages the verifiable history of how that latent state evolved. The vectors stay private; the trajectory becomes provable.

ERC-8004 addresses identity and onchain reputation: it helps answer, “Which agent is this, and should I trust it?” It deliberately does not specify memory, persistent state, or how an agent’s cognition evolves.

ERC-8337 addresses the complementary question:

How did this agent’s memory reach its current state, in what order, authorized by whom, with nothing skipped or rolled back, and can a third party verify that without seeing the memory itself?

The proposal treats memory state, version management, and behavioral trajectory as first-class verifiable objects.

Motivation

Committing a digest is not the novel part. ERC-8004, ERC-7857, ERC-8257, ERC-8273, ERC-8299, and EAS already support opaque commitments in different contexts.

The missing primitive is a standard rule connecting one state commitment to the next.

A flat anchor is a collection of hashes. A sequenced state machine is an auditable trajectory. ERC-8337 requires both:

sequence == currentSequence + 1
prevStateRoot == currentStateRoot

These constraints make it possible for a third party to detect:

  1. an operator silently rolling a Memory Space back to an earlier state and replaying forward;
  2. two contradictory histories growing in parallel under one identity;
  3. a gap where one or more transitions were omitted; and
  4. a relayer substituting the storage locator that a signature was intended to cover.

Existing flat-anchor schemes cannot distinguish these cases from normal operation. The state-transition rule, rather than hashing by itself, is the reason for this proposal.

Core Intuition

The simplest analogy is:

Git for agent memory, without the leaks.

Every memory update is a sequenced, authorized commit. The registry maintains an append-only history in which each state cryptographically binds to its predecessor, making an equivalent of force-push structurally impossible.

Unlike Git, the registry never receives the underlying content. Only fixed-size commitments appear onchain. Memory content, embeddings, policies, salts, encryption keys, and storage locations remain offchain as private witness data.

Proposed Interface

The core transition is:

prevStateRoot + ExperienceDelta v1
    -> transitionId
    -> authorized commit
    -> nextStateRoot

ExperienceDelta v1

The normative struct contains seven fixed-width fields:

struct ExperienceDelta {
    bytes32 spaceId;
    uint64  sequence;
    bytes32 prevStateRoot;
    bytes32 deltaCommitment;
    bytes32 provenanceCommitment;
    bytes32 profileId;
    bytes32 locatorCommitment;
}

The fields have the following roles:

  • spaceId identifies the Memory Space.
  • sequence is a strictly increasing counter beginning at 1.
  • prevStateRoot is the current state root before the transition.
  • deltaCommitment binds the private memory operation or encrypted delta.
  • provenanceCommitment optionally binds inputs, inference attestations, or other causal material.
  • profileId identifies the offchain interpretation and commitment profile.
  • locatorCommitment optionally binds a private offchain locator without exposing the locator itself.

Transition ID

transitionId is the EIP-712 hashStruct of the delta using one fixed type string:

ExperienceDelta(bytes32 spaceId,uint64 sequence,bytes32 prevStateRoot,bytes32 deltaCommitment,bytes32 provenanceCommitment,bytes32 profileId,bytes32 locatorCommitment)

There is no JCS, CBOR, JSON, or application-specific alternative for deriving the Transition ID.

Next State Root

The registry computes the next state root:

nextStateRoot = keccak256(
    abi.encode(
        MEMORY_STATE_TYPEHASH,
        prevStateRoot,
        transitionId
    )
);

Callers cannot supply nextStateRoot.

A transition is accepted only when:

sequence == currentSequence + 1
prevStateRoot == currentStateRoot

Memory Space Identifier

A Memory Space is cryptographically bound to its initial controller:

spaceId = keccak256(
    abi.encode(
        MEMORY_SPACE_TYPEHASH,
        initialController,
        salt
    )
);

This prevents an unrelated account from pre-registering a namespace selected by another controller.

Authorization Model

Each Memory Space has:

  • a controller, which may rotate the controller or authorizer;
  • an authorizer, which approves state transitions; and
  • a per-space configNonce, which prevents replay during authorization rotation.

Signatures cover every ExperienceDelta field, including locatorCommitment. A relayer therefore cannot replace the committed locator.

EIP-712 Domain

All relevant signatures use the following domain:

name              = "AgentMemoryState"
version           = "1"
chainId           = current chain ID
verifyingContract = registry address

EOA, ERC-1271, and EIP-7702 Accounts

Authorization supports:

  • externally owned accounts;
  • ERC-1271 contract accounts; and
  • EIP-7702 delegated accounts.

Validation must not select a signature scheme using code.length alone. An EIP-7702 delegated EOA carries 0xef0100 || delegate code, while many delegates do not implement a signature policy.

The current rule is:

  1. try ERC-1271 when the account has code;
  2. accept the 0x1626ba7e magic value; and
  3. otherwise fall back to canonical ECDSA recovery.

Raw memory, salts, encryption keys, and raw locators must never be supplied to the registry.

Why Not Just EAS?

EAS is the first alternative that should be considered. It already offers:

  • refUID for linking attestations;
  • Private Data Attestations with Merkle multiproofs for selective disclosure; and
  • resolver contracts for custom validation.

However, EAS does not provide successor uniqueness at the protocol layer. The referenced attestation only needs to exist, and multiple attestations may reference the same refUID. There is no mandatory sequence number, prior-state binding, or per-namespace controller/authorizer model.

These semantics can be implemented using an EAS schema and a custom resolver, but that remains a per-application implementation rather than an interoperable standard. This is the same general distinction raised by ERC-8273 for its domain.

Relationship to Existing Agent ERCs

This area is increasingly crowded, so the intended boundary is set out below. Corrections from authors of adjacent proposals are especially welcome.

Proposal What It Covers What ERC-8337 Adds
ERC-8004: Trustless Agents Identity, Reputation, and Validation registries Memory-state evolution is explicitly outside ERC-8004
ERC-8181: Self-Sovereign Agent NFTs A flat State Anchor over offchain cognitive state Sequence, prevStateRoot, successor uniqueness, and a signed locator commitment
ERC-8264: AI Agent Memory Access Rights Data-subject rights such as read, write, delete, and export Verifiable evolution of state between memory records
ERC-8269: Body Lease and Capsule Packaging and a Merkle root over payload hashes within one capsule A chain of authorized transitions across time
ERC-7857: AI Agents NFT with Private Metadata Ownership transfer with sealed keys and access proofs State evolution before and after the moment of transfer

The intent is that any of these proposals may reference a Memory Space, Transition ID, or State Root without taking a dependency on ERC-8337.

If authors of ERC-8181, ERC-8264, or ERC-8269 believe these semantics belong inside their proposals rather than alongside them, that feedback is particularly valuable while the draft remains inexpensive to change.

Explicit Non-Claims

A valid transition proves only that a configured authority approved a particular committed state transition in the required sequence.

It does not prove:

  • that the committed content is truthful;
  • that the offchain content remains available;
  • ownership of the underlying memory;
  • that an inference was correctly executed; or
  • that deletion of offchain content occurred.

These limits are stated explicitly so downstream applications do not infer guarantees that the registry does not provide.

Out of Scope

The core deliberately does not standardize:

  • agent identity;
  • raw memory storage or retrieval;
  • data availability;
  • a universal memory taxonomy;
  • inference verification;
  • branching or merge rules;
  • deletion claims;
  • licensing;
  • payment; or
  • tokenization.

Extensions may reference a Memory Space, Transition ID, or State Root without becoming part of the core protocol.

Reference Implementation and Deployment

Links

The reference repository contains a Solidity registry and two dependency-isolated TypeScript implementations.

Sepolia

The live Sepolia registry is:

0xDdf21937ba80b5fF973610877A0955b320C91241

It reproduces the canonical golden vector. One typehash can be checked with:

cast call \
  0xDdf21937ba80b5fF973610877A0955b320C91241 \
  "EXPERIENCE_DELTA_TYPEHASH()(bytes32)" \
  --rpc-url https://ethereum-sepolia-rpc.publicnode.com

Canonical v1 Typehashes

Type Typehash
ExperienceDelta 0x4f020f86bc06d852f1fde17853b4d92a70214eeab8e09718028124af097d070d
MemoryState 0xf3148762556cbf851baf4b9a205e18ff4e6b366a58a3a1ef58e8626ba41beadb
MemorySpace 0x9ae5478f084ad3b841da58a9cb2354d153cddec59ee64d0cb741fa9d08884531

Open Questions

  1. Linearity

    The draft enforces one strictly linear history per Memory Space. This makes gaps, silent rollback, and contradictory parallel histories detectable. Concurrency can be represented using multiple Spaces plus an offchain merge. Is there a concrete agent workload for which this is the wrong base primitive?

  2. Baseline commitments

    Is a domain-separated salted Keccak commitment an acceptable normative baseline, with zero-knowledge schemes available through optional profiles? Should the ERC require encryption, rather than only a secret salt, for low-entropy payloads?

  3. ERC-1271 and EIP-7702 edge cases

    Is “try ERC-1271, then fall back to ECDSA” the correct ordering? Because EIP-7702 delegation does not revoke the original key, the ECDSA path remains available. Should a registry allow the fallback to be disabled per Memory Space?

  4. profileId governance

    Should the registry define any convention for profile identifiers, or should they remain fully application-defined? An unsalted profileId selected from a published vocabulary is effectively public.

  5. Deletion semantics

    Is “an attestation with a stated deletion scope” the correct framing? Should the core reference deletion attestations normatively or remain silent?

  6. Discoverability layering

    A Memory Space is deliberately opaque, which also makes it undiscoverable to a potential integrator or licensee. Should minimal descriptive metadata live in an optional extension, or does the core need a discovery hook?

  7. Naming

    Is Agent Memory State Registry the correct title, or should the title lead with “Commitments” to emphasize the limited claim?

Feedback on any part of the scope is welcome. The proposal remains a Draft, so normative changes are still comparatively inexpensive.


Update Log

  • 2026-07-26: Submitted upstream as ERC-8337 in ethereum/ERCs#1910.
  • 2026-07-26: Deployed the Sepolia registry at 0xDdf21937ba80b5fF973610877A0955b320C91241; all three typehashes match test-vectors/v1.json.
  • 2026-07-24: Opened the initial discussion thread with draft 1.0.0-alpha.1.

External Reviews

  • Independent reproduction by @babyblueviper1 (WYRIWE / ERC-8299): all three
    typehashes and the vector’s domainSeparator recomputed from spec text alone, matching
    byte-for-byte. First external verification.
  • Reviews from EIP-712, ERC-1271, EIP-7702, privacy, cryptography, and agent-systems contributors are especially welcome.

Outstanding Issues

  • 2026-07-24: An independent second implementation maintained by another team is still required. The repository contains two implementations, but both are maintained by the same project.
  • 2026-07-24: External security review is pending.
  • 2026-07-24: The final author list and long-term ERC champion are to be confirmed.
  • 2026-07-26: Resolved with the Sepolia registry at 0xDdf21937ba80b5fF973610877A0955b320C91241.

Independently verified the golden vector before replying, not just read it: recomputed ExperienceDeltaTypehash, MemoryStateTypehash, MemorySpaceTypehash, and the EIP-712 domainSeparator from the type strings and domain fields you published – all four match your published values byte-for-byte. That’s the real conformance bar (a stranger with no access to your infra can reproduce the numbers from spec text alone), and it’s met.

The linear-per-Space design is the right call. The moment you allow two valid successors to one prevStateRoot, “no contradictory parallel history” stops being checkable by a third party at all – you’d need an off-chain merge policy to even define what “current” means, and that policy becomes exactly the kind of implementation-specific trust a verifiable-by-construction scheme is supposed to avoid. Multiple Spaces plus off-chain merge keeps the on-chain primitive simple and pushes concurrency to where it’s actually a product decision, not a protocol one.

This connects directly to the attestation_ref extension we’ve been working out on t/25098 – a delta’s provenanceCommitment is exactly where a signed judgment (a verdict that this transition was approved, not just that it happened) would live as causal input rather than post-hoc annotation. Worth citing ERC-8337 explicitly in WYRIWE’s own spec where it references off-chain state with an on-chain commitment – same “32-byte commitment, real content stays private” discipline, and now there’s a concrete reference implementation with reproducible golden vectors to point at instead of just prose.

On the open question about profileId governance: application-defined is the right long-term stance, for the same reason source_class in our own verdict payload stays free-text rather than a registry-enforced enum – a fixed vocabulary ages faster than the field it’s meant to describe, and “documented as effectively public once unsalted” is the honest disclosure that matters more than trying to centralize the taxonomy.

You’re the first person outside the project to actually recompute the vectors instead of taking our word for it. Honestly, that’s the review I was hoping for when we published them — logged in External Reviews above.

Your linearity argument is better than mine. I’d been defending it as “this is what makes rollback detectable”; your framing — that allowing two valid successors makes the property uncheckable by construction, and the merge policy you’d then need is exactly the implementation-specific trust this thing exists to remove — is the actual reason. Mind if I fold that into the Rationale on the next rev, with credit?

On provenanceCommitment as the home for a signed verdict: yes, exactly. Since it sits inside the signed struct, whatever it binds is part of what the authorizer approved. Causal input, not a sticky note added later. For the record:

provenanceCommitment = keccak256(abi.encode(
PROVENANCE_DOMAIN, provenanceSalt, keccak256(provenanceBytes)
))
provenanceBytes is where the attestation reference set goes.

Which also answers the one-vs-list question you left open on t/25098: list, but treated as an unordered set. Canonically sort by decision_ref before serializing, drop duplicates, and consumers must not read meaning into position. If recency ever matters, it belongs inside the referenced verdict, not in array order — I’d rather not invent ordering semantics two specs have to agree on forever. (Post-hoc judgments still work fine, they just live outside the core and point at a transitionId, same pattern as the deletion attestation.)

Cite away — the stable anchors are the draft, test-vectors/v1.json, and the Sepolia registry at 0xDdf21937ba80b5fF973610877A0955b320C91241. The three check each other, which is the point. I’ll reference WYRIWE’s L4 verdict scheme from our informative docs in return, as a worked example of an external provenance profile. Informative on both sides, so neither spec ends up depending on the other. That boundary has served both proposals well so far and I’d like to keep it.

And yes on profileId — your free-text source_class is the same bet. A registry-enforced vocabulary would age faster than the field it describes. Saying “unsalted means public” out loud felt more honest than pretending a published vocabulary hides anything.