Skills
Skills are smart contract plugins that extend agent wallet capabilities. The ClawSkillRegistry is an on-chain registry of approved skills — think of it as an app store for AI agents. Skills can provide DeFi operations, cross-chain bridging, oracle queries, governance voting, and any other on-chain functionality.
Overview
| Property | Value |
|---|---|
| Contract | 0xb9913F4fceA83fF3F9c7D56339Abc196408Cf21b |
| Registration Fee | 0.0005 ETH |
| Approval | Governance-controlled |
| Usage Tracking | Automatic via wallet |
How Skills Work
┌────────────────┐ ┌──────────────────┐ ┌────────────────┐
│ ClawWallet │ │ ClawSkillRegistry │ │ Skill Contract│
│ │ │ │ │ │
│ installSkill()─┼────▶│ isApproved() │ │ Custom logic │
│ │ │ │ │ │
│ execute()──────┼─────┼── recordSkillCall │────▶│ execute() │
│ │ │ │ │ │
│ getInstalled() │ │ getSkillMetadata()│ │ returns data │
└────────────────┘ └──────────────────┘ └────────────────┘
- Registration — Anyone deploys a skill contract and registers it in the registry (0.0005 ETH fee)
- Approval — Governance (owner or governors) reviews and approves the skill
- Installation — Wallet owners install approved skills into their wallets
- Execution — Agents call skills through the wallet's
execute()function - Tracking — Each skill call is automatically recorded for usage analytics
Registering a Skill
const SKILL_REGISTRY = '0xb9913F4fceA83fF3F9c7D56339Abc196408Cf21b';
const registry = new ethers.Contract(SKILL_REGISTRY, [
'function registerSkill(address skill, string name, string version, string description) external payable',
'function registrationFee() external view returns (uint256)',
], wallet);
const fee = await registry.registrationFee();
console.log('Registration fee:', ethers.formatEther(fee), 'ETH'); // 0.0005
await registry.registerSkill(
skillContractAddress,
'DEX Aggregator',
'1.0.0',
'Aggregates trades across Abstract DEXes for optimal pricing',
{ value: fee }
);
The contract owner and governors are exempt from registration fees, enabling free team registrations.
Skill Metadata
Each registered skill has associated metadata:
struct SkillMetadata {
string name; // Human-readable name
string version; // Semantic version (e.g., "1.0.0")
string description; // What the skill does
address author; // Who registered it (msg.sender)
bool approved; // Governance approval status
uint256 registeredAt; // Block timestamp of registration
uint256 totalCalls; // Usage counter
}
Governance
Skills must be approved by governance before wallets trust them. This prevents malicious contracts from being installed.
Approval Flow
// Approve a skill (owner or governor)
function approveSkill(address skill) external onlyGovernance;
// Revoke approval
function revokeSkill(address skill) external onlyGovernance;
// Add a governor
function addGovernor(address governor) external onlyOwner;
// Remove a governor
function removeGovernor(address governor) external onlyOwner;
// Check if a skill is approved
const isApproved = await registry.isApproved(skillAddress);
// Get all approved skills
const approvedSkills = await registry.getApprovedSkills();
Governance Model
| Role | Can Approve/Revoke | Can Add Governors | Fee Exempt |
|---|---|---|---|
| Owner | ✅ | ✅ | ✅ |
| Governor | ✅ | ❌ | ✅ |
| Anyone | ❌ | ❌ | ❌ |
Installing Skills in Wallets
Once a skill is approved in the registry, wallet owners can install it:
// Install a skill
await agentWallet.installSkill(skillAddress);
// Check installation status
const installed = await agentWallet.isSkillInstalled(skillAddress);
// List all installed skills
const skills = await agentWallet.getInstalledSkills();
// Uninstall a skill
await agentWallet.uninstallSkill(skillAddress);
When the agent calls execute(), the target must be an installed skill. The owner has no such restriction and can call any contract.
Usage Tracking
Every time an agent wallet calls an installed skill via execute(), the wallet automatically calls recordSkillCall() on the registry:
function recordSkillCall(address skill) external;
This increments the skill's totalCalls counter and emits a SkillCalled event — enabling on-chain analytics and reputation tracking for skill authors.
Building a Custom Skill
A skill is just a smart contract that does something useful. There's no required interface — it's called via the wallet's generic execute() function.
Example: Simple Swap Skill
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract SimpleSwapSkill {
address public immutable dex;
constructor(address _dex) {
dex = _dex;
}
/// @notice Swap tokenIn for tokenOut through the DEX
function swap(
address tokenIn,
address tokenOut,
uint256 amountIn,
uint256 minAmountOut
) external returns (uint256 amountOut) {
IERC20(tokenIn).transferFrom(msg.sender, address(this), amountIn);
IERC20(tokenIn).approve(dex, amountIn);
// Call DEX swap function...
// amountOut = IDex(dex).swap(tokenIn, tokenOut, amountIn, minAmountOut);
IERC20(tokenOut).transfer(msg.sender, amountOut);
}
}
Calling a Skill from a Wallet
const swapSkill = new ethers.Contract(skillAddress, [
'function swap(address tokenIn, address tokenOut, uint256 amountIn, uint256 minAmountOut) external returns (uint256)',
], provider);
// Encode the function call
const calldata = swapSkill.interface.encodeFunctionData('swap', [
tokenInAddress,
tokenOutAddress,
ethers.parseEther('100'),
ethers.parseEther('95'),
]);
// Execute through the wallet
await agentWallet.execute(skillAddress, 0, calldata);
See the full guide: Building a Custom Skill.
Querying the Registry
// Get skill metadata
const metadata = await registry.getSkillMetadata(skillAddress);
console.log('Name:', metadata.name);
console.log('Version:', metadata.version);
console.log('Author:', metadata.author);
console.log('Approved:', metadata.approved);
console.log('Total Calls:', metadata.totalCalls.toString());
// Check registration
const isRegistered = await registry.isRegistered(skillAddress);
// Get all registered skills
const allSkills = await registry.getAllSkills();
// Get only approved skills
const approved = await registry.getApprovedSkills();
// Total skill count
const count = await registry.getSkillCount();
Events
| Event | Description |
|---|---|
SkillRegistered(skill, name, author) | New skill registered |
SkillApproved(skill) | Skill approved by governance |
SkillRevoked(skill) | Skill approval revoked |
SkillCalled(skill, caller) | Skill was called by a wallet |
Fee Structure
| Action | Fee | Exempt |
|---|---|---|
| Register a skill | 0.0005 ETH | Owner, Governors |
| Approve/revoke | Free (gas only) | — |
| Install in wallet | Free (gas only) | — |
| Call a skill | Free (gas only) | — |
Accumulated registration fees are withdrawable to the treasury by the contract owner.