@lucid-agents/identity
v2.5.0
Published
ERC-8004 identity helpers for Lucid agent kit surfaces
Downloads
171
Readme
@lucid-agents/identity
ERC-8004 identity helpers for Lucid agents. Register your agent on the ERC-8004 registry and include verifiable on-chain identity in your agent manifest.
What is ERC-8004?
ERC-8004 is an Ethereum standard for an on-chain agent registry. In v1.0, agents are represented as ERC-721 NFTs with metadata stored off-chain.
Key Concepts
- Agent Identity: Agents are NFTs - registering mints an NFT to your address
- Registration file: Agent registration JSON is hosted at your domain
- Ownership: Transfer the NFT to transfer agent ownership
- On-Chain Verification: Anyone can verify agent ownership via the blockchain
What Can You Do?
This package enables you to:
- Register Agent Identity: Mint an ERC-721 NFT representing your agent on-chain with a verifiable domain
- Build Trust: Integrate verifiable identity into your agent's manifest so other agents and users can verify ownership
- Manage Reputation: Give and receive peer feedback through the reputation registry to build trust over time
- Validate Work: Request validation of your agent's work or validate other agents' outputs through the validation registry
Installation
bun add @lucid-agents/identityQuick Start
1. Set Up Environment Variables
Create a .env file:
# Your agent's domain
AGENT_DOMAIN=my-agent.example.com
# Blockchain connection
# See "Supported Networks" section for all available chains
RPC_URL=https://sepolia.base.org
CHAIN_ID=84532 # Base Sepolia (default)
# Your wallet private key (for registration)
PRIVATE_KEY=0xYourPrivateKeyHere
# Optional: Auto-register if not found
REGISTER_IDENTITY=true2. Register Your Agent
import { createAgentIdentity } from '@lucid-agents/identity';
// Register with auto-configuration from env vars
const identity = await createAgentIdentity({
autoRegister: true,
});
console.log(identity.status);
// "Successfully registered agent in ERC-8004 registry"
if (identity.didRegister) {
console.log('Transaction:', identity.transactionHash);
// The package will automatically log the registration JSON you need to host
}3. Host Your Registration File
After successful registration, the package automatically generates and logs the registration JSON you need to host. Simply copy it and save it at:
https://my-agent.example.com/.well-known/agent-registration.jsonYou can also generate a custom registration file using the helper:
import { generateAgentRegistration } from '@lucid-agents/identity';
const registration = generateAgentRegistration(identity, {
name: 'My Agent',
description: 'An intelligent assistant',
image: 'https://my-agent.example.com/og.png',
services: [
{
name: 'A2A',
endpoint: 'https://my-agent.example.com/.well-known/agent-card.json',
},
],
});
// Host this JSON at your domainUsage with Agent Kit
import { createAgentIdentity, getTrustConfig } from '@lucid-agents/identity';
import { createAgentApp } from '@lucid-agents/core';
// 1. Create identity with all three registry clients
const identity = await createAgentIdentity({
domain: 'my-agent.example.com',
autoRegister: true,
});
// 2. Create agent with trust metadata
const { app, addEntrypoint } = createAgentApp(
{
name: 'my-agent',
version: '1.0.0',
},
{
trust: getTrustConfig(identity), // Include ERC-8004 identity
}
);
// 3. Use registry clients for reputation and validation
if (identity.clients) {
// Check reputation before hiring another agent
const agentToHire = 42n;
const reputation = await identity.clients.reputation.getSummary(agentToHire);
const score =
reputation.valueDecimals === 0
? Number(reputation.value)
: Number(reputation.value) / 10 ** reputation.valueDecimals;
if (score > 80) {
console.log('Agent has good reputation, proceeding...');
}
}Working with Registry Clients
createAgentIdentity() returns clients for all three ERC-8004 registries. These clients enable you to interact with the on-chain reputation and validation systems.
const identity = await createAgentIdentity({ autoRegister: true });
// Access all three registry clients
identity.clients.identity; // Identity NFT management
identity.clients.reputation; // Peer feedback system
identity.clients.validation; // Work validationHow to Manage Identity Metadata
Read and update agent metadata:
const { identity: identityClient } = identity.clients;
// Read metadata
const metadata = await identityClient.getMetadata(myAgentId, 'version');
if (metadata) {
console.log('Version:', new TextDecoder().decode(metadata));
}
// Update metadata
await identityClient.setMetadata(
myAgentId,
'version',
new TextEncoder().encode('1.0.0')
);Transfer identity
The Identity Registry is ERC-721-like and EVM-only. You can transfer an identity token to another EVM address, or allow an approved spender to transfer on your behalf.
Transfer (owner): Transfer your identity token to another address. Uses safeTransferFrom; the signer must be the current owner.
const { identity: identityClient } = identity.clients;
// Transfer identity to another EVM address (you must be the owner)
const txHash = await identityClient.transfer(recipientEvmAddress, myAgentId);TransferFrom (owner or approved spender): Transfer a token from one address to another. The signer must be the current owner or an address approved via approve or setApprovalForAll.
await identityClient.transferFrom(fromAddress, toAddress, agentId);Approve / setApprovalForAll: Allow another address to transfer your identity token(s). After approval, that address can call transferFrom.
// Approve a single token
await identityClient.approve(approvedAddress, myAgentId);
// Approve an operator for all your tokens
await identityClient.setApprovalForAll(operatorAddress, true);
// Read approved address for a token (no wallet required)
const approved = await identityClient.getApproved(myAgentId);Addresses must be valid EVM (0x-prefixed) addresses; Solana addresses are not supported.
Example A — Register then transfer: Platform (e.g. server or CDP wallet) registers an identity, then transfers it to a user's EVM address:
const result = await client.register({
agentURI: 'https://my-agent.example.com/.well-known/agent-registration.json',
});
if (result.agentId) {
await client.transfer(userEvmAddress, result.agentId);
}Example B — Transfer only: Signer already owns an identity; transfer it to another EVM address:
await client.transfer(recipientEvmAddress, agentId);For Coinbase CDP (Lucid MCP / xgate), use a viem-compatible WalletClient backed by your CDP server account (same interface: account.address, writeContract). See the xgate-mcp-server adapter for the CDP pattern. Runnable scripts: examples/register-then-transfer.ts, examples/transfer-only.ts, and examples/deploy-agent.ts (register + optional transfer).
How to Manage Reputation
Give and receive feedback on agent interactions:
const { reputation } = identity.clients;
// Give feedback to another agent
await reputation.giveFeedback({
toAgentId: 42n,
value: 90, // integer; use valueDecimals for fixed-point
valueDecimals: 0,
tag1: 'reliable',
tag2: 'fast',
endpoint: 'https://my-agent.example.com/api', // Optional parameter (defaults to empty string if not provided)
feedbackURI: 'ipfs://QmFeedbackDetails', // Optional, defaults to empty string
});
// Query reputation
const summary = await reputation.getSummary(42n);
const average =
summary.valueDecimals === 0
? Number(summary.value)
: Number(summary.value) / 10 ** summary.valueDecimals;
console.log(`Agent #42: ${average}/100 (${summary.count} reviews)`);
// Get all feedback
const feedback = await reputation.getAllFeedback(42n);
// Revoke feedback you gave
await reputation.revokeFeedback({
agentId: 42n,
feedbackIndex: 5n,
});
// Respond to feedback you received
await reputation.appendResponse({
agentId: myAgentId,
clientAddress: '0x...',
feedbackIndex: 3n,
responseUri: 'ipfs://QmMyResponse',
responseHash: '0x...',
});How to Validate Work
Note: Validation Registry is deprecated and under active development. It will be revised in a follow-up spec update later this year. The API has been updated to match the new ABI but remains deprecated. If
requestBodyis not provided, the client hashesrequestUrifor backward compatibility.
Request validation of your work or validate others:
const { validation } = identity.clients;
if (validation) {
// Create validation request (function renamed: createRequest → validationRequest)
await validation.validationRequest({
validatorAddress: '0x...',
agentId: myAgentId,
requestUri: 'ipfs://QmMyWork',
// Prefer hashing the canonical request body (spec-compliant)
requestBody: '{"input":"work-data"}',
// Or pass requestHash directly if you already have one
// requestHash: keccak256(toHex('work-data')),
});
// Submit validation response (function renamed: submitResponse → validationResponse)
// Tag type changed: bytes32/Hex → string
await validation.validationResponse({
requestHash: '0xabc...',
response: 1, // 1 = valid, 0 = invalid
responseUri: 'ipfs://QmValidationReport',
responseHash: '0x...',
tag: 'validation', // Now a string, not bytes32
});
// Query validations (tag type changed: bytes32/Hex → string)
const requests = await validation.getAgentValidations(myAgentId);
const summary = await validation.getSummary(myAgentId, {
tag: 'validation', // Now a string, not bytes32
});
console.log(`${summary.count} validations, avg: ${summary.avgResponse}`);
}Supported Networks
The package supports multiple EVM-compatible chains. Set CHAIN_ID and RPC_URL in your environment:
- Ethereum Mainnet (1)
- Sepolia Testnet (11155111)
- Base Mainnet (8453)
- Base Sepolia (84532) - default
- Arbitrum (42161)
- Optimism (10)
- Polygon (137)
- Polygon Amoy (80002)
Examples
See the examples/ directory for complete examples:
register-then-transfer.ts- Example A: Register an identity, then transfer it to a user's EVM addresstransfer-only.ts- Example B: Transfer an existing identity token to another EVM addressdeploy-agent.ts- Deploy agent identity (register on ERC-8004 registry, optionally transfer to a user). Required env:RPC_URL,CHAIN_ID,PRIVATE_KEY,AGENT_URI. Optional:TRANSFER_TO. For CDP wallet, use a WalletClient backed by your CDP server account (see xgate-mcp-server).
API Reference
createAgentIdentity(options)
Main function to set up ERC-8004 identity for your agent.
Options:
{
// Agent domain (defaults to AGENT_DOMAIN env var)
domain?: string;
// Auto-register if not found (default: true)
autoRegister?: boolean;
// Blockchain configuration
chainId?: number; // Default: 84532 (Base Sepolia)
rpcUrl?: string; // Default: RPC_URL env var
privateKey?: string; // Default: PRIVATE_KEY env var
// Trust configuration
trustModels?: string[]; // Default: ["feedback", "inference-validation"]
trustOverrides?: {
validationRequestsUri?: string;
validationResponsesUri?: string;
feedbackDataUri?: string;
};
// Environment and logging
env?: Record<string, string | undefined>;
logger?: {
info?(message: string): void;
warn?(message: string, error?: unknown): void;
};
}Returns:
{
// Whether agent was newly registered
didRegister?: boolean;
isNewRegistration?: boolean;
// Transaction hash (if registered)
transactionHash?: string;
// Agent record (if found/registered)
record?: {
agentId: bigint;
owner: string;
agentURI: string;
};
// Trust config for agent manifest
trust?: TrustConfig;
// Human-readable status message
status: string;
// Resolved domain
domain?: string;
}registerAgent(options)
Convenience wrapper that forces autoRegister: true.
const identity = await registerAgent({
domain: 'my-agent.example.com',
});getTrustConfig(identity)
Extract just the trust config from an identity result.
const identity = await createAgentIdentity({ autoRegister: true });
const trustConfig = getTrustConfig(identity);
// Use in createAgentApp
createAgentApp({ name: 'my-agent' }, { trust: trustConfig });generateAgentRegistration(identity, options?)
Generate the registration JSON to host at your domain. Automatically called after registration, but you can also use it to customize the registration file.
const registration = generateAgentRegistration(identity, {
name: 'My Agent',
description: 'An intelligent assistant',
image: 'https://my-agent.example.com/og.png',
services: [
{
name: 'A2A',
endpoint: 'https://my-agent.example.com/.well-known/agent-card.json',
},
],
});
// Save to: https://your-domain/.well-known/agent-registration.jsonHow It Works
When you call createAgentIdentity({ autoRegister: true }):
- Registers your agent on-chain (mints an NFT to your address)
- Returns a trust config for your agent manifest
- Provides clients for reputation and validation
You must host the registration file at: https://{your-domain}/.well-known/agent-registration.json
The trust config allows other agents to verify your identity and access reputation data.
Troubleshooting
"No ERC-8004 identity" Message
If you see this message, it means:
- Agent isn't registered yet (set
autoRegister: true) - Registry connection failed (check RPC_URL)
- Wallet not configured (check PRIVATE_KEY)
This is normal - your agent will run fine without on-chain identity, it just won't have verifiable trust metadata.
Registration Succeeded but No Trust Config
After successful registration (didRegister: true), the package can't immediately verify the registration because ERC-8004 v1.0 doesn't support querying by domain. This is expected behavior.
Solution: Query by agent ID later, or trust that the transaction succeeded.
Registration File Not Accessible
Make sure your registration file is:
- Hosted at the exact URL:
https://{domain}/.well-known/agent-registration.json - Returns valid JSON with
Content-Type: application/json - Accessible over HTTPS (not HTTP)
- Not blocked by CORS (if accessed from browsers)
License
MIT
