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


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:
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.
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.
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.
@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
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:
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.@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.@acl/negotiation accepts any AxlBridge-compatible client, so an alternative encrypted transport drops in cleanly — the default is Gensyn AXL.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.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.*.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:
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.: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.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.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.
AXL is the only transport between agents. No central broker, no in-process bus, no fallback HTTP route:
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.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.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.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.
Three 0G surfaces do different jobs, but the guarantees they give are joined on chain:
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.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.(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.
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.
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.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.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.
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.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.
taskSpec-vs-Job.description check fires spuriously.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.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.waitForReceiptResilient survives transient null responses from the public 0G RPC during reorg / propagation lag, so the demo doesn't flake on public-endpoint glitches.txSeq, so provider re-runs and evaluator re-derivations are safe.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.

