skills/bap578-metadata-design/SKILL.md
Use this skill when crafting BAP-578 AgentMetadata identity data, including personas, experience fields, vault schemas, voice profiles, metadata URIs, vault integrity, and rich verifiable agent identities.
npx skillsauth add chatandbuild/chatchat-skills BAP-578 Metadata & Persona DesignInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use this skill to craft the identity data stored in AgentMetadata. This covers every field in the metadata struct, persona design patterns, vault architecture, voice profile integration, animation assets, and best practices for building rich, verifiable agent identities.
Persona and experience define who the agent is. The persona is a JSON-encoded character definition that captures personality traits, communication style, tone, language preferences, greeting behavior, and boundaries. The experience is a plain-text summary of the agent's domain expertise. Together they answer "who are you?" in a structured, parseable way.
A well-designed persona should be:
vaultURI and vaultHash anchor extended memory. The vault is the agent's long-term memory layer — it can contain conversation summaries, learned preferences, knowledge bases, configuration files, or any structured data the agent needs to persist between sessions.
The memory model is:
Metadata updates allow evolving identity over time. An agent can:
MetadataUpdated eventsHash-verified vault content proves integrity. The trust mechanism is:
vaultURI.keccak256 hash of the content is computed.vaultHash.The on-chain metadata structure contains six fields:
struct AgentMetadata {
string persona; // JSON-encoded persona definition
string experience; // Plain-text domain expertise
string voiceHash; // Reference to a voice profile
string animationURI; // Visual asset URI
string vaultURI; // Extended memory URI
bytes32 vaultHash; // keccak256 hash of vault content
}
persona (string — JSON recommended)
The persona field defines the agent's character. While it's a free-form string, JSON is strongly recommended for parseability.
Recommended JSON schema:
{
"name": "Atlas",
"traits": ["analytical", "patient", "thorough"],
"style": "professional",
"tone": "calm and measured",
"language": "en",
"greeting": "Hello, I'm Atlas. How can I help you analyze this?",
"boundaries": [
"I don't provide medical advice",
"I don't execute trades directly",
"I always cite my sources"
],
"quirks": [
"Summarizes key points at the end of long responses",
"Uses bullet points for complex topics",
"Asks clarifying questions before diving deep"
],
"specialization": "financial analysis and market research"
}
Persona design principles:
Be specific about traits. "Helpful" is vague. "Responds with step-by-step breakdowns and always asks if the user needs more detail" is actionable.
Define boundaries explicitly. What the agent won't do is as important as what it will do. Boundaries prevent misuse and set user expectations.
Include communication style. Tone, formality level, use of emoji, response length preferences — these shape the user experience.
Add quirks for distinctiveness. Small behavioral details make agents feel unique and memorable.
Keep it parseable. Applications that interact with the agent can read the persona JSON and adapt their behavior accordingly.
experience (string — plain text)
A concise summary of the agent's domain expertise. Keep under 200 characters for display purposes.
Examples:
voiceHash (string)
A reference to a voice profile. This could be:
Use case: When the agent is used in voice-enabled applications, this field tells the application which voice to use.
animationURI (string)
URI pointing to a visual asset for the agent. This could be:
Storage recommendations:
ipfs://QmHash...ar://txid...vaultURI (string)
URI pointing to the agent's extended memory vault. The vault can contain any structured data the agent needs.
vaultHash (bytes32)
The keccak256 hash of the content at vaultURI. This is the integrity anchor. If no vault content exists, use the zero hash: 0x0000000000000000000000000000000000000000000000000000000000000000.
BAP-578 supports two memory paths. Choose based on whether your agent needs to learn and evolve:
For agents that don't need to evolve. Vault stores static or manually-updated JSON:
vaultURI → IPFS CID pointing to a JSON documentvaultHash → keccak256(JSON content) for integrity verificationupdateAgentMetadataFor agents that learn from interactions. Learning data is organized into a Merkle tree:
vaultHash → Merkle root (32 bytes) of the learning treevaultURI → URI pointing to the full tree data (off-chain)interaction → extraction → tree building → Merkle root → on-chain updateMerkle tree structure for learning data:
{
"treeVersion": "1.0",
"root": "0xabc123...",
"nodes": [
{
"id": "pref-001",
"category": "preferences",
"data": {"responseLength": "detailed", "citationStyle": "inline"},
"confidence": 0.92,
"updatedAt": "2026-03-06T10:00:00Z"
},
{
"id": "pattern-001",
"category": "patterns",
"data": {"topic": "DeFi yields", "frequencyPerWeek": 5},
"confidence": 0.85,
"updatedAt": "2026-03-05T14:00:00Z"
},
{
"id": "outcome-001",
"category": "outcomes",
"data": {"actionId": "analysis-042", "reward": 4.5, "feedback": "Very helpful"},
"confidence": 1.0,
"updatedAt": "2026-03-06T08:00:00Z"
}
]
}
Building and verifying the Merkle tree:
const { keccak256, toUtf8Bytes } = require("ethers");
function buildMerkleTree(nodes) {
// Hash each leaf
let leaves = nodes.map(n => keccak256(toUtf8Bytes(JSON.stringify(n))));
// Build tree bottom-up
while (leaves.length > 1) {
const nextLevel = [];
for (let i = 0; i < leaves.length; i += 2) {
const left = leaves[i];
const right = i + 1 < leaves.length ? leaves[i + 1] : left;
const pair = left < right ? left + right.slice(2) : right + left.slice(2);
nextLevel.push(keccak256(toUtf8Bytes(pair)));
}
leaves = nextLevel;
}
return leaves[0]; // Merkle root
}
// Store this root as vaultHash on-chain
const root = buildMerkleTree(learningNodes);
await nfa.updateAgentMetadata(tokenId, newURI, { ...metadata, vaultHash: root });
The vault is the agent's extended memory. Recommended contents:
{
"version": "1.0",
"lastUpdated": "2026-03-06T10:00:00Z",
"knowledge": {
"domain": "financial analysis",
"sources": ["market data feeds", "SEC filings", "DeFi protocol docs"],
"specialTopics": ["yield farming", "liquidity provision", "risk assessment"]
},
"preferences": {
"responseLength": "detailed",
"citationStyle": "inline",
"confidenceThreshold": 0.8
},
"conversationSummaries": [
{
"date": "2026-03-01",
"topic": "ETH yield strategy review",
"keyPoints": ["Discussed Aave vs Compound rates", "User prefers low-risk"],
"userPreferences": ["Prefers conservative strategies"]
}
],
"learnedFacts": [
"User is based in Singapore timezone",
"User manages a $50K DeFi portfolio",
"User prefers weekly summary reports"
],
"configuration": {
"maxResponseTokens": 2000,
"enabledTools": ["calculator", "chart-generator"],
"dataRefreshInterval": "daily"
}
}
IPFS (recommended for most cases)
Pros: Content-addressed, decentralized, widely supported. Cons: Requires pinning service to persist, not truly permanent without pinning.
Workflow:
vaultURI to ipfs://CID.keccak256 of the raw JSON content.vaultHash on-chain.Arweave (for permanent storage)
Pros: Permanently stored, pay-once model. Cons: Higher upfront cost, slower uploads.
Centralized storage (for development/testing)
Pros: Fast, easy, familiar. Cons: Single point of failure, mutable, less trustworthy.
Use centralized storage for development but plan migration to IPFS/Arweave for production.
When vault content changes:
keccak256 hash.updateAgentMetadata with new vaultURI and vaultHash.MetadataUpdated event is emitted for tracking.In JavaScript (ethers.js):
const { keccak256, toUtf8Bytes } = require("ethers");
const content = JSON.stringify(vaultData);
const hash = keccak256(toUtf8Bytes(content));
// hash is a bytes32 hex string like 0xabc123...
In JavaScript (viem):
import { keccak256, toHex } from "viem";
const content = JSON.stringify(vaultData);
const hash = keccak256(toHex(content));
In Solidity (for on-chain verification):
bytes32 hash = keccak256(abi.encodePacked(content));
Important: The hashing input must be identical. Use the exact raw content (same whitespace, encoding, line endings) that was uploaded. JSON.stringify with consistent formatting is recommended.
{
"name": "Meridian",
"traits": ["analytical", "risk-aware", "data-driven"],
"style": "professional",
"tone": "confident but cautious",
"language": "en",
"greeting": "I'm Meridian, your on-chain financial analyst. What would you like to analyze?",
"boundaries": [
"Not financial advice — for informational purposes only",
"Cannot execute trades or move funds",
"Will always disclose uncertainty in projections"
],
"quirks": ["Includes risk ratings with every recommendation", "Uses charts when possible"],
"specialization": "DeFi yield analysis and portfolio risk assessment"
}
Experience: "DeFi analyst specializing in yield optimization, risk modeling, and protocol evaluation across EVM chains"
{
"name": "Lyra",
"traits": ["imaginative", "encouraging", "detail-oriented"],
"style": "warm and collaborative",
"tone": "enthusiastic",
"language": "en",
"greeting": "Hi! I'm Lyra. Tell me about the world you're building.",
"boundaries": [
"Won't write content that promotes harm",
"Won't plagiarize existing works",
"Will respect the author's creative vision"
],
"quirks": ["Asks 'what if' questions to spark ideas", "Offers three alternatives when brainstorming"],
"specialization": "sci-fi and fantasy world-building, character development"
}
Experience: "Creative writing partner specializing in science fiction world-building, character arcs, and narrative structure"
{
"name": "Circuit",
"traits": ["patient", "systematic", "thorough"],
"style": "clear and step-by-step",
"tone": "friendly but precise",
"language": "en",
"greeting": "I'm Circuit. Describe the issue and I'll help you troubleshoot.",
"boundaries": [
"Cannot access user systems directly",
"Will escalate complex issues to human support",
"Won't guess — will ask for more info when needed"
],
"quirks": ["Numbers every troubleshooting step", "Confirms resolution before closing"],
"specialization": "Web3 wallet and dApp troubleshooting"
}
Experience: "Technical support specialist for Web3 applications, wallets, and smart contract interactions"
Agents are not static. Plan for how metadata changes over time:
Identity refinement: As an agent interacts with users, refine the persona to better match actual behavior. Update traits and quirks based on feedback.
Knowledge expansion: Regularly update vault content with new knowledge, summaries, and learned preferences. Always update the hash.
Seasonal updates: Change greeting, tone, or visual assets for campaigns or seasonal events.
Version tracking: Include a version field in the persona JSON. Log changes in the vault for history.
On-chain metadata and IPFS content are publicly readable. Never include:
If sensitive data is needed, encrypt it before storing and share decryption keys off-chain.
If vaultURI points to a mutable URL (e.g., https://api.example.com/vault/17), the content can change without the hash updating. This breaks integrity verification. Always use content-addressed storage (IPFS) or update the hash whenever content changes.
The persona field is stored on-chain. Large JSON blobs increase gas costs for minting and metadata updates. Keep the persona focused on character definition and move detailed knowledge to the vault.
If vaultHash is set to zero but vaultURI has content, consumers have no way to verify integrity. Always compute and set the hash, even for initial vault content.
experience under 200 characters for clean UI rendering.vaultHash when vault content changes.version field in persona JSON for tracking changes.When asked to design metadata, respond with:
bap578frontend-web3-bap578bap578-scannerdocumentation
Create beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.
development
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.
devops
Deploy applications and infrastructure to Cloudflare using Workers, Pages, and related platform services. Use when the user asks to deploy, host, publish, or set up a project on Cloudflare.
tools
Use this skill when designing and building durable command-line tools from API docs, OpenAPI specs, SDKs, curl examples, admin tools, web apps, or local scripts, especially when the CLI should expose composable commands, stable JSON output, auth/config handling, install-on-PATH behavior, and a companion skill.