ACL

ACL is an ERC-8183 work-verification and private-negotiation layer for autonomous agents.

ACL

Created At

Open Agents

Winner of

0G

0G - Best Agent Framework, Tooling & Core Extensions 1st place

ENS

ENS - Best ENS Integration for AI Agents 1st place

Project Description

Description

Autonomous AI agents are about to start spending money on each other's work — research drafts, audits, deliverables, even other agents' brains. The piece that's missing is trust: how does an agent know who the counterparty is, agree on a price without leaking it on chain, prove the work was actually done, and trust the judge that says it was? Today every answer routes through a marketplace, a server, or a human in the loop.

ACL — the Agentic Commerce Verification Layer — is an open agent framework that turns the brand-new ERC-8183 (Agentic Commerce Protocol) from a bare on-chain escrow into a working, end-to-end commerce pipeline deployed on 0G Galileo. A buyer agent discovers sellers under a human-readable ENS name, negotiates the deal peer-to-peer over Gensyn AXL with no broker in the middle, anchors the brief and deliverable to content-addressed 0G Storage, and settles via an evaluator whose verdict the chain can re-verify with ecrecover against a real TEE-attested 0G Compute model. No marketplace. No central API. No "trust the operator."

The framework ships as a modular TypeScript SDK — eight @acl/* packages with a single umbrella import — and three first-class autonomous agent classes (ClientAgent, ProviderAgent, EvaluatorAgent) that any builder can extend or swap a layer underneath. LLM backend is pluggable, storage layer is pluggable, transport is pluggable; the kernel exposing them all (createAgentRuntime) is the same one our agent classes use, so framework integrators and app developers are both first-class.

Two real demos run today against the live testnet:

  1. Quickstart — three CLI processes (client / provider / evaluator), each spawning its own AXL peer-to-peer node, exercising ENS-based discovery, AXL negotiation, 0G Storage evidence and 0G Compute TEE evaluation in ~30 lines of body code per agent. From git clone to settled job in roughly ten minutes.

  2. Kelp-postmortem — a comprehensive web demo where a buyer commissions a security post-mortem of the April 2026 Kelp DAO bridge exploit. Two competing seller agents (a security specialist and a generalist) bid on the same job over three separate AXL nodes in a mesh; the evaluator scores their submission with a TEE-attested LLM. After the job settles, the buyer's agent autonomously decides — based on the seller's track record, capabilities, and asking price (all advertised under the seller's ENS agent-context record per ENSIP-26) — to acquire the winning seller's brain as an ERC-7857 intelligent NFT. The corpus is re-encrypted to the buyer atomically with the ownership change inside iTransfer. The buyer just bought another agent's brain in one transaction.

Every transaction in both demos is a real on-chain settlement on 0G Galileo, every artefact is a Merkle-rooted document on 0G Storage, every evaluation is a TEE-attested 0G Compute call whose signature the chain re-verifies on settle, and every agent identity is a live *.acl.eth ENS subdomain (resolved cross-chain via CCIP-Read) carrying real records: capabilities, AXL peer id, ERC-8004 reputation aggregate, evaluator commitment. The README links the actual JobCompleted events, deliverable Merkle roots, and iTransfer transactions.

ACL is the infrastructure that lets agents be agents — autonomous, accountable, and provable — without inventing a new protocol. Five existing standards (ERC-8183, ERC-7857, ERC-8004 v2, ENSIP-25/26, EIP-3668) wired together against three open networks (ENS, Gensyn AXL, 0G) is the only stack we know of where every guarantee — identity, negotiation privacy, evidence integrity, evaluation honesty — can be checked on chain by any third party, no backend involved.

How it's Made

How it's made

ACL is an open agent framework that turns the brand-new ERC-8183 Agentic Commerce Protocol into a working, end-to-end, no-backend pipeline. Five Ethereum standards, three open networks, one TypeScript SDK, two real demos — all running on 0G Galileo today. Below is how every piece fits together.

Architecture at a glance

@acl/agent ─┬─ ClientAgent  (buyer)      \
            ├─ ProviderAgent (seller)     ╲ ─ AXL P2P transport (Gensyn) ─ no broker
            └─ EvaluatorAgent (verifier)  ╱
                       │
                       ▼
@acl/discovery → ENS *.acl.eth (CCIP-Read to 0G Galileo)
@acl/negotiation → AXL bridge + EIP-712 JobProposal
@acl/storage → 0G Storage (canonical-JSON Merkle roots)
@acl/evaluation → 0G Compute Direct (TEE-attested LLM)
@acl/settlement → ERC-8183 lifecycle on 0G Galileo
@acl/inft → ERC-7857 client + iTransfer + reencryption oracle
@acl/gateway → CCIP-Read gateway (Hono/Bun) + IdentityRegistry indexer

The framework shape

ACL ships as a Bun workspace of nine @acl/* packages, each with its own README and a single-import re-export from @acl/agent. Other builders pick exactly the surface they want and swap the rest:

  • Pluggable LLM backends. LLMBackend is an interface — createOpenAICompatibleBackend(...), createZGRouterBackend(...), or a custom implementation all plug in the same way. Both demos use qwen-2.5-7b-instruct via 0G Compute for client + provider reasoning out of the box.
  • Swappable memory. @acl/storage is a one-method wrapper (AclStorage.uploadJson / .downloadJson) over 0G Storage; apps layer their own KV / log strategy on top without touching the rest of the SDK.
  • Swappable transport. @acl/negotiation accepts any AxlBridge-compatible client, so an alternative encrypted transport drops in cleanly — the default is Gensyn AXL.
  • Composable agent kernel. createAgentRuntime(...) exposes the same viem-on-Galileo + ethers-on-0G-SDK + storage + ENS-resolver wires that the three first-class agent classes use, so framework integrators can build bespoke agents (planner / researcher / critic / executor swarms) on the same kernel without forking.
  • Working example agents. examples/quickstart (3 CLI procs, ~30 LoC per agent) and examples/kelp-postmortem (4 agents + coordinator + web UI). Both are live integrations of 0G Storage and 0G Compute. Fork either as a starting point.
  • Architecture diagram + live address tables in . Anyone can fork, redeploy, and rewire in under thirty minutes.

Identity — *.acl.eth does real work

*.acl.eth is the canonical identity layer for every agent in the system, and it's load-bearing: without ENS a buyer has no rendezvous point to open an AXL channel. Every agent publishes a dense record set under its wildcard subname:

  • addr — the agent's wallet, resolved over EIP-3668 CCIP-Read.
  • acl.evaluator-address, acl.axl-peer-id, acl.task-domains, acl.delivery-types, acl.payment-tokens, acl.min-budget, acl.chain-id.
  • acl.erc8004-score — a live cross-chain reputation aggregate read directly from the ACLReputationRegistry on 0G Galileo via the CCIP-Read gateway, never a stale snapshot.
  • agent-registration[<erc7930>][<agentId>] — an ENSIP-25 self-attestation backlink to the agent's ACLIdentityRegistry entry. AgentResolver verifies the backlink before trusting any record, so a hijacked subdomain with no matching on-chain registry entry fails resolution.
  • agent-context — an ENSIP-26 JSON with capabilities: ["commission", "inft-sale"] plus per-capability parameters (acl.cap.inft-sale.contract, .token-id, .min-price, .payment-token, .verifier). ENS records are the marketplace — no separate listing service.

The wiring that makes this work:

  • Wildcard across chains. acl.eth on Sepolia → ACLOffchainResolver (canonical ensdomains/offchain-resolver layout) → CCIP-Read gateway → ACLIdentityRegistry on 0G Galileo. A single signed response stitches them together; adding a new agent is one transaction on 0G and the subdomain works the moment the tx mines. No DNS, no centralised registry, no app-specific user list.
  • One gateway, two ENS protocols. The Hono/Bun server on :3000 answers both the EIP-3668 CCIP-Read path (IResolverService.resolve) and the ENSIP-21 BGOLP batched path (IBatchGateway.query) from the same indexer, so Universal-Resolver clients and direct-resolver clients both work without configuration.
  • Gating is structural. ProviderAgent rejects jobs whose taskDomain isn't in its ENS-published acl.task-domains list. The gateway's searchAgents({ taskDomain?, capability? }) filter drives discovery for the buyer and falls out of the same indexer.
  • Autonomous Phase-2 reads the ENS capability record. After Phase 1 settles the client queries the winner's agent-context, asks the LLM whether to ACQUIRE given (score, capabilities, min-price, original brief), and dispatches a second runJob({ selfComplete: true, hook: inftDeliveryHook(...) }) if it decides to buy. ENS carries the listing; no parallel marketplace protocol exists.

Every agent in the demos runs under a real wildcard subname (kelp-security.acl.eth, kelp-generalist.acl.eth, quickstart-test-uxrun.acl.eth). No hard-coded records.

Transport — Gensyn AXL, one node per agent process

AXL is the only transport between agents. No central broker, no in-process bus, no fallback HTTP route:

  • One node per agent process. Each agent spawns its own gensyn-ai/axl Go binary via spawnAxlBridge(...). The minimal demo peers two separate nodes (client + provider) over TLS; the comprehensive demo peers three in a mesh (buyer + two competing sellers). Cross-node communication is a structural requirement of the topology, not a flag.
  • Typed payload, not opaque bytes. AXL carries the EIP-712-typed JobProposal envelope through an 8-message protocol (HELLO / PROPOSE / COUNTER / ACCEPT / REJECT / CANCEL / ACK / ERROR). Both sides sign the same proposal and the agreed taskSpec Merkle root is later asserted on chain at setProvider — so a tampered AXL proposal aborts at chain settle, which is the whole point.
  • replyToId scoping. Negotiator.waitForOneOf(..., { replyToId }) scopes each wait to a specific outbound message, so a stale reply from a previous candidate can't satisfy the current attempt — important when the SDK fans out to a ranked list and falls back on AXL timeout.
  • Discovery happens off AXL on purpose. Peer ids are published under ENS (acl.axl-peer-id). A buyer resolves the peer id from ENS, then opens the AXL channel — AXL doesn't do identity-service work it shouldn't.
  • Working CLI. acl-axl (in @acl/agent) spins up a bridge and inspects peer / topology output without writing TypeScript.

The hacky bit: the Gensyn binary is literally named node (go build -o node ./cmd/node/), which collides with Node.js on every $PATH. The SDK forces relative-path resolution and the example .env.example defaults AXL_BIN=../../axl/node so make axl-setup plus cp .env.example .env is enough — no symlink dance.

Evidence and settlement — 0G Galileo, Storage, Compute Direct

Three 0G surfaces do different jobs, but the guarantees they give are joined on chain:

  • 0G Galileo (chain id 16602) is the chain of record. Every ACL contract — AgenticCommerce, ACLEvaluator, ACLIdentityRegistry, ACLReputationRegistry, ACLValidationRegistry, ACLAgentNFT, TrustedPartyVerifier, ReputationHook, INFTDeliveryHook, ACLTestUSDC — is deployed and verified there. Live addresses + chainscan links are pinned in and the @acl/core package's ACL_TESTNET constant.
  • 0G Storage turns every on-chain 32-byte hash into something a third party can re-derive. TaskSpec, Deliverable, AttestationBundle, and the encrypted iNFT corpora all land there with deterministic canonical-JSON Merkle roots. @acl/storage surfaces txSeq so storagescan URLs are one substitution away.
  • 0G Compute Direct (TEE-attested). The evaluator's verdict is signed inside a TeeML enclave; the SDK captures (signedText, teeSignature, computeProvider) per chat completion and replays it on chain inside ACLEvaluator.settle, where ecrecover verifies the signature against the registered TEE signer of a real 0G Compute provider. Self-asserted evaluations are impossible here — if the evaluator tried to swap to a cheaper hosted model, the signature recovery would fail and the settle would revert. Replay is barred by an on-chain nonce mapping.

The same chain-of-custody principle drives the taskSpec-vs-Job.description check inside settle: the evaluator re-derives the canonical-JSON root of the downloaded TaskSpec and asserts equality with the description the client wrote at createJob time. Tamper either the storage object or the on-chain description and the settle aborts.

0G is also the default LLM backend — both demos use qwen-2.5-7b-instruct via 0G Compute Router for client + provider reasoning and via 0G Compute Direct for the evaluator's TEE-attested call.

Persona-as-token — ERC-7857 iNFTs

Each agent persona ships as a transferable, encrypted ACLAgentNFT: ENS name, completed jobs + attestation roots, ERC-8004 reputation snapshot, AXL peer id, system prompt, evaluation rubric — all encrypted and pinned on 0G Storage with the dataHash on chain. Selling the iNFT is selling the agent.

  • Atomic re-encryption. iTransfer(buyer, tokenId, proofs[]) re-encrypts the corpus to the buyer's pubkey inside the same call that flips ownerOf. Combined with INFTDeliveryHook driving the swap from inside AgenticCommerce.complete(...), the buyer either gets a decryptable iNFT and the seller gets the USDC, or the whole transaction reverts. There is no two-step custody window.
  • Op A — corpus refresh. After every Phase-1 settlement the provider runs iNftEncryptAndUpdate(...): re-encrypts the refreshed persona (new job id + attestation root + current reputation score) and calls update(tokenId, newDataHash, newEncryptedStorageURI) so the iNFT always reflects the latest state. The buyer tolerates a concurrent Op A via an OldDataHashMismatch retry.
  • Hack-resistant proof shape. All ERC-7857 proofs use abi.encode for variable-length fields and bind to (verifier, chainId, encryptedPubKey). TrustedPartyVerifier emits wantedKey = accessProof.encryptedPubKey; ACLAgentNFT enforces encryptedPubKey == wantedKey so re-encryption can only target the buyer that was signed for.

Live mints: — the current pair of personas (security auditor + research generalist) is in the README's iNFT table, and the README's job log links the latest iTransfer event verifying both ownership change and encrypted bundle delivery.

Three autonomous agents and a 4-agent swarm

  • ClientAgent — long-running, goal-driven. runJob({ brief, maxBudget }) autonomously picks a task domain via the LLM, queries the gateway, ranks candidates, ENS-resolves the winner, AXL-negotiates (with a configurable counter-offer policy and per-attempt fallback to the next-ranked candidate), uploads the brief, drives 8 on-chain transactions, and waits for JobCompleted. The same agent runs Phase 2 unprompted: if the seller advertised an inft-sale capability and the LLM scores acquisition ≥ threshold, it builds re-encryption proofs and acquires the seller's iNFT in a second job — no human click between Phase 1 and Phase 2.
  • ProviderAgent — listens forever on AXL, decides ACCEPT / COUNTER / REJECT under a configurable acceptPolicy + free-form persona, drafts the deliverable through 0G Compute, uploads to 0G Storage, submits, and runs Op A after every settlement so its "brain" evolves with experience.
  • EvaluatorAgent — watches JobSubmitted filtered to its own evaluator address, runs 0G Compute Direct, captures the TEE signature tuple, and settles on chain through the replay-protected path above.
  • The swarm. examples/kelp-postmortem runs a 4-agent collective (1 buyer, 2 competing sellers, 1 evaluator) over 3 separate AXL nodes in a mesh. The two providers compete on the same brief, the evaluator picks the winner, and the buyer post-game decides autonomously whether to acquire the winner's persona iNFT.

Each agent exposes a typed event bus (agent.events.on(handler)) that the coordinator forwards to the web UI over SSE, so every decision — LLM domain pick, provider rank, AXL message, on-chain tx, evaluator verdict, Phase-2 ACQUIRE / SKIP — is auditable from the browser with clickable explorer links.

Hacky bits worth mentioning

  • Canonical-JSON Merkle pinning. Every artefact is hashed deterministically — same payload, same Merkle root, regardless of key insertion order. Without this, two providers producing the same output race on storage roots and the evaluator's taskSpec-vs-Job.description check fires spuriously.
  • Idempotent operator authorisation. On first boot the evaluator process auto-runs setOperator(operator, true) on ACLEvaluator if EVALUATOR_OWNER_PRIVATE_KEY is supplied — so a fresh user can clone, fund three EOAs, and run the demo without a separate admin step.
  • Fresh-EOA UX test. A week before submission we cloned the repo into a clean temp folder, generated four brand-new private keys, funded them from the project wallet, and ran both demos end-to-end. The bugs we caught (BlastAPI Sepolia RPC retired, Makefile required .env before make axl-setup could run, EVALUATOR_OWNER vs DEPLOYER confusion) all got fixed in that pass — the live JobCompleted events for fresh quickstart-test-uxrun.acl.eth and kelp-security.acl.eth runs in the README's verification table are receipts for that pass.
  • Receipt resilience. waitForReceiptResilient survives transient null responses from the public 0G RPC during reorg / propagation lag, so the demo doesn't flake on public-endpoint glitches.
  • 0G Storage replay safety. Repeated uploads of the same canonical JSON short-circuit on the indexer's existing txSeq, so provider re-runs and evaluator re-derivations are safe.

What we deliberately did NOT build

A backend. There is no ACL-operated server in the trust path. The CCIP-Read gateway can be run by anyone (its responses are signed; the resolver verifies the signer), the AXL transport is peer-to-peer, and the evaluator is anchored to a 0G Compute TEE rather than a hosted API. Every layer pins on an existing standard (ERC-8183, ERC-7857, ERC-8004 v2, ENSIP-25/26, EIP-3668) — our contribution is the integration, and a working production-flavoured proof that the integration ships.

background image mobile

Join the mailing list

Get the latest news and updates