SBO3L — Mandate-Based Policy Boundary for Autonomous Agents

Hi ENS community,

I’m opening this discussion thread for SBO3L, a mandate-based policy boundary for autonomous AI agents.

The core idea is:

Don’t give your agent a wallet. Give it a mandate.

SBO3L is a local policy, signing, and audit boundary that sits in front of an autonomous agent before it can execute sensitive actions such as swaps or on-chain transactions.

Instead of giving the agent direct wallet access, the operator defines a bounded mandate with rules such as:

  • allowed tokens

  • maximum notional value

  • maximum slippage

  • quote freshness window

  • recipient / treasury rules

  • audit and proof requirements

For the prototype, we used ENS as an identity and discovery layer for the agent.

We registered:

sbo3lagent.eth

and published sbo3l:* ENS text records that can be resolved by a live resolver, including:

  • sbo3l:agent_id

  • sbo3l:endpoint

  • sbo3l:policy_hash

  • sbo3l:audit_root

  • sbo3l:proof_uri

The goal is to explore whether ENS can serve as a readable, decentralized identity and metadata layer for autonomous agents, where an agent’s endpoint, mandate hash, audit root, and proof reference are discoverable through ENS records.

Prototype links:

I would appreciate feedback from the ENS developer community on:

  1. Whether this is a reasonable use of ENS text records for agent identity and metadata discovery.

  2. Whether the sbo3l:* namespace is appropriate, or if there is a better convention.

  3. Whether this pattern could be useful for autonomous agents, policy-bound wallets, or agent-to-agent coordination.

  4. Any security, naming, resolver, or UX concerns we should consider.

Thank you — happy to provide more technical details or adjust the approach based on feedback.

3 Likes

There has been interest in the ENS community in agent-specific text records. ENSIP-26 was just merged, which introduces a standard for ENS agent text records. Currently, it is challenging to know which records will be generally important and standard for onchain agents. What we have now is:

  1. An entry point record, agent-context

  2. An endpoint record that can support more than one endpoint type, agent-endpoint[<type>], e.g. agent-endpoint[mcp]

Would this work for your project? One pattern I am imagining is using markdown in the agent-context record with embedded JSON in a code block that is specific to your protocol for example. I think, over time, if clear common patterns emerge for onchain agents, more text records could be added to ENSIP-26.

Hi Premm,

thank you — this is very helpful.

Yes, I think this pattern could work well for SBO3L.

Our original prototype used custom sbo3l:* text records mainly because we wanted to expose agent identity, endpoint, policy hash, audit root, and proof URI in a simple way.

But if ENSIP-26 is now defining a standard entry point for agent identity and discovery, it makes sense for us to align with that instead of pushing a separate custom namespace as the primary pattern.

The way I imagine SBO3L fitting into ENSIP-26 is:

  • agent-context as the main human/machine-readable context record for the agent

  • agent-endpoint[mcp] or another endpoint type for connecting to the agent / policy service

  • SBO3L-specific mandate and proof metadata embedded inside agent-context, likely as markdown with a JSON code block, as you suggested

For example, the agent-context could describe:

  • what the agent is allowed to do

  • which chains/protocols it supports

  • which policy or mandate applies

  • where proof/audit records can be found

  • which endpoint can be used to request or verify actions

And the embedded SBO3L-specific JSON could include fields such as:

{
  "protocol": "sbo3l",
  "agent_id": "research-agent-01",
  "mandate_hash": "0x...",
  "policy_hash": "0x...",
  "audit_root": "0x...",
  "proof_uri": "https://...",
  "supported_actions": ["swap", "payment", "workflow_execution"],
  "supported_chains": ["eip155:1", "eip155:8453"]
}

That would let ENS remain the standard discovery layer, while SBO3L keeps the mandate / policy / proof semantics inside the context.

Longer term, if mandate hashes, policy pointers, proof URIs, or audit roots become common across agent systems, those could potentially become separate standardized records later.

For now, I agree that agent-context + agent-endpoint[<type>] seems like the right place to start.

One question from my side:

Would you recommend that SBO3L keeps all protocol-specific metadata inside agent-context for now, or would it still be acceptable to also publish optional custom records like sbo3l:policy_hash / sbo3l:proof_uri as convenience records while treating ENSIP-26 as the canonical path?

For the question of text records, it is more about function over style. Individual text records can cost more or less gas, depending on how they are used.

For setting records once with embedded JSON, the cost is lower than with many individual text records. For updating individual records, the cost is higher.

Within agent-context it’s possible to reference other text records, using ERC-8121 Hooks, if you want a formal way to do it.

For SBO3L, I think the cleanest approach is to align with ENSIP-26 and use agent-context as the canonical entry point, with SBO3L-specific mandate / policy / proof metadata embedded as JSON there.

Then agent-endpoint[<type>] can point to the agent or policy endpoint.

We’d avoid many separate custom sbo3l:* records unless there is a strong reason to update them independently. ERC-8121 hooks sound like a good later option if we need formal references to mandate or proof registries.

Does that sound like the right direction from an ENS perspective?

1 Like

I am just a developer who works on ENS, but from my perspective that sounds good. :+1:

I would also recommend taking a look at draft ENSIP-64 ( ENSIP: Node Classification And Metadata by jmacwhyte · Pull Request #64 · ensdomains/ensips · GitHub ). It allows you to publish a json schema file that describes which keys will be present on your ENS name, making them machine readable. Instead of needing to create a standard that defines all the keys you want to use and try to get people to follow it, you can just design and publish a schema file and every ENSIP-64 consumer would automatically be able to read and display all your keys, even if they don’t know anything about your use case. People who want to publish compatible metadata to work with your system can just use your same schema. We already have a UI + SDK + CLI that makes it easy for them to pick a schema and set the records.

Here’s a guide in the docs about how it could work for an AI agent using our reference schema (compatible with ERC-8004) but it should give you a good idea how it could work with your own schema: AI Agents – ENS Organizational Registry

1 Like

Thanks jkm, this is very useful.

I think this may actually be a better fit for SBO3L than trying to push many custom text records as a standard.

The way I understand it, we could use:

  • ENSIP-26 agent-context / agent-endpoint[...] as the standard agent discovery layer

  • ENSIP-64 to publish an SBO3L-specific JSON schema describing the mandate / policy / proof metadata

  • the actual ENS records then become machine-readable even for clients that do not know SBO3L in advance

For SBO3L, the schema could describe fields like:

  • mandate hash

  • policy hash

  • proof URI

  • supported action types

  • supported chains

  • workflow / execution permissions

  • audit or receipt pointers

That feels cleaner than asking everyone to adopt sbo3l:* records directly.

I’ll take a closer look at ENSIP-64 and the AI agent registry example. One question: would you recommend that SBO3L publishes its own schema and references it from the ENS name, while keeping agent-context as the main entry point?

This is the use case we envision with ENSIP-64 (with no prior indexing required):

  1. We start with an ENS name/subname
  2. The client requests the schema record for the name
  3. If found, the client requests each key specified in the schema file and validates the results for type or other restraints specified

Keys that exist on the name but aren’t specified in the schema won’t be retrieved, which is intended behavior. We expect it will be common for schema files to also include global key names which have been declared in other standards (like description, avatar, etc).

So to answer your question, you could create a schema file which also includes the agent-context and agent-endpoint[...] records and explains how you expect these keys to be used. An ENSIP-64-enabled client will read the schema and learn that you are intending to use these keys, and can then retrieve them. Any clients that don’t know about ENSIP-64 but are searching for agent-context will still pick up the value you’ve set and will be able to handle it correctly. This demonstrates how multiple standards can all work together cleanly.

I would recommend copying our agent schema file as a starting point, and adding in the additional values you need. We could add your version into our main repo and serve it up as one of the canonical reference schemas for others to use.

Hi @B2JK-Industry, @Premm.eth, and jkm.eth —

I wanted to jump in here because this thread is converging on something I’ve been thinking about for a while, and it intersects directly with work I’ve done analyzing tokenomic systems.

@B2JK-Industry, the core thesis — “don’t give your agent a wallet, give it a mandate” — addresses a problem that already caused real damage in DeFi well before autonomous agents entered the picture. Protocols that gave smart contracts broad treasury access without bounded policy constraints lost funds. Not because of exploits — because the authority model was wrong. The contract could do things no one intended, and eventually it did. SBO3L is applying that lesson to the agent layer, and the six cryptographic checks in the Passport capsule (structural validation, JCS+SHA-256 request hash recompute, policy hash recompute, Ed25519 receipt signature, audit chain verification, audit event linkage) give this real teeth. The fact that the verifier compiles to WASM and runs client-side with zero network calls is exactly the right trust model.

One pattern I keep seeing across protocols with similar problem-sets (full access vs. policies): the protocols that survived weren’t the ones with the most flexible authority models. They had the tightest bounded authority models. Compound’s governance timelock, Uniswap’s fee-switch constraints, Aave’s risk parameter ceilings — these are mandate patterns applied at the contract level. SBO3L extends that pattern to autonomous agents, and the approach of making the agent create carry zero signing dependencies is the right architectural boundary.

On the ENS integration question — I think the ENSIP-26 + ENSIP-64 stack is the right path, but the thread is underselling what it enables.

@Premm.eth, your suggestion to use agent-context with embedded JSON and agent-endpoint[<type>] for discovery is clean, and it follows the composability patterns that work well across ENS. The gas cost argument for bundling metadata into a single agent-context record versus many individual sbo3l:* records is practical and correct.

jkm.eth, draft ENSIP-64 adds something important that I think deserves more emphasis: it makes the SBO3L mandate schema self-describing to any ENSIP-64 consumer. That’s a significant difference from just embedding JSON in a text field. With ENSIP-64, a client that has never heard of SBO3L can resolve sbo3lagent.eth, read the schema record, fetch the JSON schema, and immediately understand what mandate_hash, policy_hash, proof_uri, supported_actions, and supported_chains mean — including type constraints and validation rules. That’s a prerequisite for agent-to-agent coordination. If Agent A needs to verify Agent B’s mandate before interacting with it, having a machine-readable schema at the ENS layer eliminates an entire class of integration problems.

@B2JK-Industry’s proposed JSON structure (protocol, agent_id, mandate_hash, policy_hash, audit_root, proof_uri, supported_actions, supported_chains) maps cleanly to an ENSIP-64 schema. The suggestion to copy the existing agent schema from ensmetadata.app and extend it with SBO3L-specific fields is the fastest path to something usable.

Two things I’d push on:

1. Policy versioning needs to be explicit in the schema. If an operator updates a mandate (tighter slippage limits, new allowed tokens, changed notional caps), the old policy_hash and the new one need to coexist during a transition window. Otherwise, you get a race condition where an agent resolves one policy hash, the operator updates, and the Passport capsule the agent produces references a policy that no longer matches what’s on-chain. The schema should include a policy_version or policy_effective_from timestamp. This is the same problem DeFi governance timelocks solve — you don’t want policy changes to take effect mid-flight.

2. The audit_root should be anchored, not just referenced. Right now the proof page shows that audit chain integrity is verified by signature and prev-hash linkage within the capsule. That’s good for offline verification. But for third-party trust — say, a protocol that wants to verify an agent’s history before granting it execution permissions — the audit_root should be periodically anchored on-chain (or at minimum to a content-addressed store like IPFS with the CID published as an ENS record). James’s suggestion about ERC-8121 Hooks for referencing other records could work here: the agent-context points to the schema, the schema includes an audit_root field, and a separate record (or a hook reference) carries the latest on-chain anchor. This gives you both offline self-verification and on-chain attestation without overloading a single record.

On the broader question of whether ENS can serve as the identity and metadata layer for autonomous agents:

Yes, and it should. The alternative is every agent framework inventing its own registry, which fragments discovery and makes cross-framework coordination impossible. ENS already has the resolver infrastructure, the text record extensibility, and the namespace governance to handle this. ENSIP-26 gives agents a standard entry point. ENSIP-64 makes their metadata self-describing. SBO3L adds the policy and audit semantics on top. That’s a clean stack.

The one thing I’d watch is gas costs for frequent policy updates. If an operator is updating mandates regularly (new token allowlists, adjusted budgets), the cost of updating ENS records on mainnet adds up. L2 subname resolvers or off-chain resolvers with CCIP-Read could help here, and it would be worth thinking about whether the SBO3L schema should explicitly support indicating which resolver chain the policy metadata lives on.

Good work on all sides of this thread. The convergence from custom sbo3l:* records to the ENSIP-26/64 standard path is the right move, and the prototype is already further along than most agent identity proposals I’ve seen.

— Robby | Tokedex.org

1 Like

ERC-8121, I think, also provides a necessary piece of the puzzle for onchain agent identity.

It allows for statements by third parties to be made about an agent. Endorsements, for example a security review, i.e. a red team review, of the agent cannot be saved in the metadata of the agent, because then it would be updatable by the owner of the agent. It needs to be saved in a third-party registry. ERC-8121 is designed to create a web of trust, where the reputation of the credential issuer provides meaningful reputation to the agent via the endorsement. A hook is a specially formatted function call that contains all the required metadata, allowing a client to resolve the metadata from another contract.

hook(“getOwner(uint256)”, “getOwner(42)”, “(address)”, 0x000100000101141234567890abcdef1234567890abcdef12345678)

It can also work cross-chain, using ERC-7930 interoperable addresses, meaning that an agent can build a reputation from multiple chains using multiple credentials and endorsements.

1 Like

Hi Robby, Premm — thank you both, this is extremely useful.

Robby, I really appreciate the depth of your analysis. The comparison with bounded authority patterns in DeFi governance and risk systems is exactly the mental model behind SBO3L: agents should not receive broad authority by default; they should operate inside explicit, verifiable constraints.

I also agree with the direction that is emerging here:

  • ENSIP-26 as the agent discovery / context entry point

  • ENSIP-64 as the way to make SBO3L-specific mandate metadata self-describing

  • ERC-8121 hooks as a path for external references, third-party attestations, endorsements, and registries

  • SBO3L as the mandate / policy / proof layer on top

The point about policy versioning is very important. I agree that the schema should not only expose a policy_hash, but also include fields such as:

  • policy_version

  • policy_effective_from

  • policy_valid_until

  • possibly previous_policy_hash or a transition window

Otherwise, an agent could generate a valid proof capsule against a policy that was updated while the action was already in flight.

The audit root point also makes sense. The current capsule model is focused on offline verification: structural checks, hash recomputation, signature verification, and audit chain linkage. But for third-party trust, especially if another protocol or execution layer wants to evaluate an agent’s history before allowing an action, anchoring the audit root externally is much stronger.

So I think the next version should distinguish between:

  1. offline self-contained verification through the capsule

  2. external trust / reputation / history through anchored audit roots or registry references

  3. third-party endorsements through ERC-8121-style hooks or external registries

This also maps well to how I’m thinking about SBO3L beyond the prototype:

ENS can describe who the agent is and where its context lives.
SBO3L can define and verify what the agent is allowed to do.
An execution layer can then decide whether to accept or reject an agent action based on the mandate and proof.

I’ll take a closer look at ENSIP-64 and the AI agent registry example. The fastest next step from my side is probably to draft an SBO3L metadata schema that extends the existing agent schema with mandate / policy / proof fields, including explicit versioning and audit anchoring.

Thank you again — this gives a much clearer path than trying to define a separate custom sbo3l:* namespace.

1 Like

Also, ERC-8121 requires ERC-3668, CCIP-Read. This means that the data can live offchain, with an onchain verifier. Because resolving ERC-8121 data requires clients that are aware of the standard, it also allows those clients to “turn on” ERC-3668 support.

1 Like

Thanks Premm, that clarifies the architecture a lot.

So if I understand correctly, ERC-8121 + ERC-3668 means SBO3L would not need to put all mandate / audit / endorsement data directly into ENS records or onchain storage.

Instead, ENS can remain the discovery layer, while the heavier or more frequently updated data can live offchain or on another chain, with CCIP-Read-aware clients resolving it and an onchain verifier checking the result.

That seems especially relevant for SBO3L because mandates, audit roots, and third-party endorsements may update more often than basic agent identity records.

So a possible direction would be:

  • ENSIP-26 for agent context / endpoint discovery

  • ENSIP-64 for machine-readable SBO3L metadata schema

  • ERC-8121 hooks for references to external registries or endorsements

  • ERC-3668 / CCIP-Read for resolving offchain or cross-chain data with verification

This feels like a much better path than trying to store everything directly in custom text records.

Text records are accessible by smart contracts and RPC calls. They include implicit authentication, because they can only be published with a cryptographic signature from the ENS name owner. On-chain records are also costly to update.

Off-chain records are cheap to host and update (just throw it on a cloud server somewhere), but they aren’t [directly] accessible to smart contracts and they don’t have the resilience and authentication built in.

The ideal solution seems to be a combination of the two. For important info that doesn’t change very often, store it on-chain in the records. For info that is important but does change frequently, you can add an on-chain record that points to an off-chain resource (e.g. add a url to a cloud server as a text record). This data won’t have the resilience of being on-chain, but you can extend the implicit authentication by having the server also provide a cryptographic signature of the payload confirming it came from the same owner as the ENS name.

This pattern is explained briefly in our docs around ENSIP-64 for agents. We describe putting the agent’s identity info directly into records (name, avatar, ERC-8004 registrations, etc) and for frequently-changing things that don’t need to be consumed by smart contracts (like whether or not the agent is currently active) just point to an off-chain resource somewhere.

The point about policy versioning is very important. I agree that the schema should not only expose a policy_hash, but also include fields such as:

  • policy_version
  • policy_effective_from
  • policy_valid_until
  • possibly previous_policy_hash or a transition window

There are a few options for this! ENSIP-64 provides for arrayed keys, so policy_hash[0] could be the first one to be issued, and policy_hash[1] could be a later version. Clients could walk through all entries in order until they run out of entries, and that would give them the entire history. You could limit the number of entries you keep around so clients don’t end up having to walk a very long list.

For details pertaining to one entry (e.g. version and timestamps apply to one specific hash) I would recommend wrapping all of those details into one string using a specific format and adding it as a single text record to guarantee atomicity.

ERC-3668 allows for offchain data to be fully verified and authenticated. The data can become unavailable, but the authority is fully onchain.

AFAIK, CCIP read is for use inside of smart contracts, and the smart contract would need to implement its own authenticity checking which the off-chain resource would also need to support. That’s what I mentioned above about the cloud server also needing to provide a signature.

If you publish a url to a web server that simply serves up a JSON payload with no additional authentication, ERC-3668 itself doesn’t really do anything to prove that that data came from the owner of the ENS name.

I agree there needs to be a verification step, but the verification step could be anything. For example, if you wanted to make sure that the result was a number between 1 and 100, that could be a form of verification.

I think the real power comes in with ZK proofs. Then you can verify basically any amount of computation. That becomes really powerful.

Thanks both — this clarifies the tradeoff a lot.

My takeaway for SBO3L is that the right model is probably hybrid:

  • stable identity / discovery data can live directly in ENS records

  • frequently changing mandate, policy, status, or audit data should live offchain or in another registry

  • but any offchain payload must still be verifiable, either through an explicit signature from the ENS owner / authorized delegate, or through a contract-based verification path such as ERC-3668 / CCIP-Read where the verifier actually checks authenticity

So I agree that simply publishing a URL to unsigned JSON would not be enough for SBO3L. The payload would need to be bound back to the ENS identity or to an authorized registry.

For policy versioning, I also like the idea of treating each policy version as an atomic object rather than splitting related fields across many records. Something like:

{
  "policy_hash": "0x...",
  "policy_version": "3",
  "policy_effective_from": "2026-05-08T12:00:00Z",
  "policy_valid_until": "2026-06-08T12:00:00Z",
  "previous_policy_hash": "0x..."
}

That way the hash, version, and timestamps cannot get out of sync.

A possible SBO3L direction could be:

  • ENSIP-26 for agent context / endpoint discovery

  • ENSIP-64 for describing the SBO3L metadata schema

  • ENS records for stable pointers and identity information

  • signed offchain policy/audit manifests for frequently changing data

  • optional ERC-3668 / ERC-8121 paths where smart-contract-readable verification is needed

This seems like a good balance between cost, updateability, and verifiability.

2 Likes