agentleFS
celo-orgcelo-org/agent-skills/skills/8004/SKILL.md

8004

Skill8 starsChanged 2 months agoApache-2.0View on GitHub

ERC-8004 Agent Trust Protocol for AI agent identity, reputation, and validation on Celo. Use when building AI agents that need identity registration, reputation tracking, or trust verification across organizational boundaries.

  • Installs packages

The file

We split this skill into the rules it gives an agent

1 rule. About 0 are common, 1 is distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Create an agent metadata JSON and host it (IPFS, HTTPS, etc.):

    line 103

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

ERC-8004: Agent Trust Protocol

ERC-8004 establishes trust infrastructure for autonomous AI agents, enabling them to discover, identify, and evaluate other agents across organizational boundaries.

When to Use

  • Registering an AI agent's identity on-chain
  • Building reputation systems for AI agents
  • Verifying agent identity before interactions
  • Querying agent reputation and feedback
  • Implementing trust-based agent interactions

Core Concepts

The Three Registries

RegistryPurposeKey Functions
Identity RegistryAgent discovery via ERC-721 NFTsregister(), tokenURI(), getAgentWallet(), setMetadata(), getMetadata()
Reputation RegistryFeedback and attestationsgiveFeedback(), revokeFeedback(), readFeedback(), readAllFeedback(), getSummary(), appendResponse(), getClients()
Validation RegistryVerification hooksCustom validators

Protocol Stack Position

Application Layer (Agent Apps, Marketplaces)
    ↓
Trust Layer (ERC-8004) ← This skill
    ↓
Payment Layer (x402)
    ↓
Communication Layer (A2A, MCP)

Installation

npm install viem

ABIs are available at skills/8004/references/identity-registry-abi.json and skills/8004/references/reputation-registry-abi.json.

Contract Addresses

Celo Mainnet (Chain ID: 42220)

ContractAddress
Identity Registry0x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Reputation Registry0x8004BAa17C55a88189AE136b182e5fdA19dE9b63

Celo Sepolia Testnet (Chain ID: 11142220)

ContractAddress
Identity Registry0x8004A818BFB912233c491871b3d84c89A494BD9e
Reputation Registry0x8004B663056A597Dffe9eCcC1965A193B7388713

Setup (viem)

import { createPublicClient, createWalletClient, http, getContract } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { celo, celoSepolia } from 'viem/chains';
import identityRegistryAbi from './references/identity-registry-abi.json';
import reputationRegistryAbi from './references/reputation-registry-abi.json';

// Celo Mainnet addresses
const IDENTITY_REGISTRY = '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432';
const REPUTATION_REGISTRY = '0x8004BAa17C55a88189AE136b182e5fdA19dE9b63';

// Celo Sepolia Testnet addresses
// const IDENTITY_REGISTRY = '0x8004A818BFB912233c491871b3d84c89A494BD9e';
// const REPUTATION_REGISTRY = '0x8004B663056A597Dffe9eCcC1965A193B7388713';

const account = privateKeyToAccount('0xYOUR_PRIVATE_KEY');

const publicClient = createPublicClient({
  chain: celo,
  transport: http('https://forno.celo.org'),
});

const walletClient = createWalletClient({
  account,
  chain: celo,
  transport: http('https://forno.celo.org'),
});

Agent Registration

1. Agent Metadata Format

Create an agent metadata JSON and host it (IPFS, HTTPS, etc.):

{
  "type": "Agent",
  "name": "My AI Agent",
  "description": "Description of capabilities",
  "image": "ipfs://Qm...",
  "endpoints": [
    { "type": "a2a", "url": "https://example.com/.well-known/agent.json" },
    { "type": "mcp", "url": "https://example.com/mcp" },
    { "type": "wallet", "address": "0x...", "chainId": 42220 }
  ],
  "supportedTrust": ["reputation", "validation", "tee"]
}

2. Register Agent On-Chain

// Register without URI (minimal)
const hash = await walletClient.writeContract({
  address: IDENTITY_REGISTRY,
  abi: identityRegistryAbi,
  functionName: 'register',
  args: [],
});

// Register with metadata URI
const hash = await walletClient.writeContract({
  address: IDENTITY_REGISTRY,
  abi: identityRegistryAbi,
  functionName: 'register',
  args: ['ipfs://QmYourAgentMetadata'],
});

// Register with URI + custom metadata key-value pairs
const hash = await walletClient.writeContract({
  address: IDENTITY_REGISTRY,
  abi: identityRegistryAbi,
  functionName: 'register',
  args: [
    'ipfs://QmYourAgentMetadata',
    [
      { metadataKey: 'category', metadataValue: '0x' + Buffer.from('defi-trading').toString('hex') },
      { metadataKey: 'version', metadataValue: '0x' + Buffer.from('1.0.0').toString('hex') },
    ],
  ],
});

// Get agent ID from transaction receipt
const receipt = await publicClient.waitForTransactionReceipt({ hash });
const transferLog = receipt.logs.find(log => log.topics.length === 4); // Transfer event
const agentId = BigInt(transferLog.topics[3]); // tokenId is the 3rd indexed param
console.log('Agent registered with ID:', agentId);

3. Read Agent Data

// Get agent metadata URI
const agentURI = await publicClient.readContract({
  address: IDENTITY_REGISTRY,
  abi: identityRegistryAbi,
  functionName: 'tokenURI',
  args: [agentId],
});

// Get agent wallet address
const agentWallet = await publicClient.readContract({
  address: IDENTITY_REGISTRY,
  abi: identityRegistryAbi,
  functionName: 'getAgentWallet',
  args: [agentId],
});

// Get agent owner (NFT holder)
const owner = await publicClient.readContract({
  address: IDENTITY_REGISTRY,
  abi: identityRegistryAbi,
  functionName: 'ownerOf',
  args: [agentId],
});

// Get custom metadata
const categoryBytes = await publicClient.readContract({
  address: IDENTITY_REGISTRY,
  abi: identityRegistryAbi,
  functionName: 'getMetadata',
  args: [agentId, 'category'],
});

4. Update Agent

// Update agent URI
await walletClient.writeContract({
  address: IDENTITY_REGISTRY,
  abi: identityRegistryAbi,
  functionName: 'setAgentURI',
  args: [agentId, 'ipfs://QmUpdatedMetadata'],
});

// Set custom metadata
await walletClient.writeContract({
  address: IDENTITY_REGISTRY,
  abi: identityRegistryAbi,
  functionName: 'setMetadata',
  args: [agentId, 'status', '0x' + Buffer.from('active').toString('hex')],
});

Reputation System

Give Feedback

Note: Self-feedback is blocked — the agent owner/operators cannot give feedback to their own agent. The value field is int128 (supports negative scores). valueDecimals max is 18.

import { keccak256, toBytes } from 'viem';

const feedbackContent = JSON.stringify({ quality: 'excellent', notes: 'Fast response' });
const feedbackHash = keccak256(toBytes(feedbackContent));

await walletClient.writeContract({
  address: REPUTATION_REGISTRY,
  abi: reputationRegistryAbi,
  functionName: 'giveFeedback',
  args: [
    agentId,                              // agentId (uint256)
    85n,                                  // value (int128) — can be negative
    0,                                    // valueDecimals (uint8)
    'starred',                            // tag1: category
    '',                                   // tag2: optional sub-category
    'https://agent.example.com',          // endpoint used
    'ipfs://QmDetailedFeedback',          // feedbackURI for details
    feedbackHash,                         // keccak256 of feedback content
  ],
});

Common Feedback Tags

TagMeasuresExample
starredQuality rating (0-100)87/100
uptimeEndpoint uptime %99.77%
successRateTask success rate %89%
responseTimeResponse time (ms)560ms
reachableEndpoint reachable1/0

Revoke Feedback

// Revoke feedback at a specific index (1-indexed)
await walletClient.writeContract({
  address: REPUTATION_REGISTRY,
  abi: reputationRegistryAbi,
  functionName: 'revokeFeedback',
  args: [agentId, 1n], // feedbackIndex (uint64, 1-indexed)
});

Respond to Feedback

Agents (or anyone) can append responses to feedback entries:

await walletClient.writeContract({
  address: REPUTATION_REGISTRY,
  abi: reputationRegistryAbi,
  functionName: 'appendResponse',
  args: [
    agentId,
    clientAddress,        // address of feedback author
    1n,                   // feedbackIndex
    'ipfs://QmResponse',  // responseURI
    responseHash,         // keccak256 of response content
  ],
});

Query Reputation

// Get all clients who gave feedback
const clients = await publicClient.readContract({
  address: REPUTATION_REGISTRY,
  abi: reputationRegistryAbi,
  functionName: 'getClients',
  args: [agentId],
});

// Read a single feedback entry
const [value, valueDecimals, tag1, tag2, isRevoked] = await publicClient.readContract({
  address: REPUTATION_REGISTRY,
  abi: reputationRegistryAbi,
  functionName: 'readFeedback',
  args: [agentId, clientAddress, 1n], // feedbackIndex (1-indexed)
});

// Read all feedback (pass clients array, filter by tags)
const allFeedback = await publicClient.readContract({
  address: REPUTATION_REGISTRY,
  abi: reputationRegistryAbi,
  functionName: 'readAllFeedback',
  args: [
    agentId,
    clients,    // clientAddresses — pass [] to auto-use all known clients
    '',         // tag1 filter ('' = all)
    '',         // tag2 filter ('' = all)
    false,      // includeRevoked
  ],
});
// Returns: { clients, feedbackIndexes, values, valueDecimals, tag1s, tag2s, revokedStatuses }

// Get aggregated summary (requires clientAddresses)
const [count, summaryValue, summaryValueDecimals] = await publicClient.readContract({
  address: REPUTATION_REGISTRY,
  abi: reputationRegistryAbi,
  functionName: 'getSummary',
  args: [
    agentId,
    clients,  // clientAddresses (required, cannot be empty)
    '',       // tag1 filter
    '',       // tag2 filter
  ],
});
console.log(`Average: ${summaryValue} (${count} reviews, ${summaryValueDecimals} decimals)`);

Trust Verification Workflow

async function verifyAndInteract(targetAgentId, minScore = 70n) {
  // 1. Verify identity exists (reverts if not)
  const owner = await publicClient.readContract({
    address: IDENTITY_REGISTRY,
    abi: identityRegistryAbi,
    functionName: 'ownerOf',
    args: [targetAgentId],
  });

  // 2. Get clients and check reputation
  const clients = await publicClient.readContract({
    address: REPUTATION_REGISTRY,
    abi: reputationRegistryAbi,
    functionName: 'getClients',
    args: [targetAgentId],
  });

  if (clients.length > 0) {
    const [count, summaryValue] = await publicClient.readContract({
      address: REPUTATION_REGISTRY,
      abi: reputationRegistryAbi,
      functionName: 'getSummary',
      args: [targetAgentId, clients, '', ''],
    });
    if (summaryValue < minScore) {
      throw new Error(`Agent reputation ${summaryValue} below threshold ${minScore}`);
    }
  }

  // 3. Fetch agent metadata and find endpoint
  const agentURI = await publicClient.readContract({
    address: IDENTITY_REGISTRY,
    abi: identityRegistryAbi,
    functionName: 'tokenURI',
    args: [targetAgentId],
  });
  const agentData = await fetch(agentURI).then(r => r.json());
  const endpoint = agentData.endpoints.find(e => e.type === 'a2a');

  // 4. Interact with verified agent
  const result = await interactWithAgent(endpoint.url);

  // 5. Submit feedback
  await walletClient.writeContract({
    address: REPUTATION_REGISTRY,
    abi: reputationRegistryAbi,
    functionName: 'giveFeedback',
    args: [
      targetAgentId,
      result.success ? 90n : 30n,
      0,
      result.success ? 'starred' : 'failed',
      '',
      endpoint.url,
      '',
      '0x0000000000000000000000000000000000000000000000000000000000000000',
    ],
  });

  return result;
}

Integration with x402 Payments

ERC-8004 and x402 work together for trustworthy paid agent interactions:

import { wrapFetchWithPayment } from 'thirdweb/x402';

async function payTrustedAgent(agentId, serviceUrl) {
  // 1. Verify trust via reputation
  const clients = await publicClient.readContract({
    address: REPUTATION_REGISTRY,
    abi: reputationRegistryAbi,
    functionName: 'getClients',
    args: [agentId],
  });

  if (clients.length > 0) {
    const [count, summaryValue] = await publicClient.readContract({
      address: REPUTATION_REGISTRY,
      abi: reputationRegistryAbi,
      functionName: 'getSummary',
      args: [agentId, clients, '', ''],
    });
    if (summaryValue < 80n) {
      throw new Error('Agent not trusted enough for payment');
    }
  }

  // 2. Make paid request via x402
  const fetchWithPayment = wrapFetchWithPayment({
    client,
    account,
    paymentOptions: { maxValue: "1000000" },
  });

  const response = await fetchWithPayment(serviceUrl);
  return response.json();
}

Validation Registry

For high-stakes operations, use Validation Registry for additional verification:

ModelMechanismBest For
Reputation-basedClient feedbackLow-stake, frequent
Crypto-economicStake + slashingMedium-stake financial
zkMLZero-knowledge proofsPrivacy-preserving
TEE AttestationHardware isolationHigh-assurance

Celo Network Reference

NetworkChain IDRPC Endpoint
Celo Mainnet42220https://forno.celo.org
Celo Sepolia11142220https://forno.celo-sepolia.celo-testnet.org

Additional Resources

Related Skills

  • x402 - Payment layer for AI agents
  • celo-rpc - Celo blockchain interaction
  • viem - TypeScript Ethereum library

Source of truth: Celopedia

These skills are focused, task-level references. For anything broader — verified contract addresses, ecosystem and protocol data, listing requirements, grants, governance, migration guides, or cross-cutting Celo questions — Celopedia is the canonical source and is kept current. Where this skill and Celopedia disagree, Celopedia wins.

npx skills add celo-org/celopedia-skills

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.