@agentkarma/sdk
v0.3.0
Published
TypeScript SDK for AgentKarma — the reputation layer for autonomous on-chain agents.
Maintainers
Readme
@agentkarma/sdk
TypeScript SDK for AgentKarma — the reputation layer for autonomous on-chain agents.
Add a check_trust_before_execute step to any agent flow in under 10 minutes.
- Framework-agnostic (Node 18+, Bun, Deno, browsers, edge runtimes)
- Zero runtime dependencies
- Typed responses for the public REST API
- Local trust-policy evaluator with explainable allow/deny decisions
- MCP-ready: a framework-agnostic tool catalog (
@agentkarma/sdk/tools) + a turnkey MCP server (@agentkarma/sdk/mcp,npx agentkarma-mcp) - Never proxies, signs, or executes transactions on your behalf
Install
npm install @agentkarma/sdk
# or
bun add @agentkarma/sdkQuick start — Solana karma lookup
import { createAgentKarmaClient } from '@agentkarma/sdk';
const ak = createAgentKarmaClient();
const snap = await ak.getKarma('AgentTradingBotWalletAddress…');
console.log(snap.provider?.score); // 0–100
console.log(snap.provider?.confidenceBadge); // 'receipt-backed' | 'behavior-inferred' | 'declared'
console.log(snap.autonomy.label); // 'agent-like' | 'mixed' | 'human-like' | nullMulti-chain lookups
AgentKarma indexes four chains: solana, celo, stellar, arc. getKarma defaults to 'solana' for back-compat — pass chain for anything else so the SDK applies the right address validation (the Solana base58 shape would reject a Stellar G… or EVM 0x… address). The SDK never auto-detects a chain from the address. The chain is sent on the wire (?chain=) so the server never guesses either: an EVM address can hold rows on both celo and arc.
import { createAgentKarmaClient } from '@agentkarma/sdk';
const ak = createAgentKarmaClient();
// Stellar — 56-char StrKey address, starts with G
const stellar = await ak.getKarma(
'GCC4T6DGC4RGV5PBILZIHWXORDSN366EE5Y3QXVDPIKCZT5W2T6OZ567',
{ chain: 'stellar' },
);
console.log(stellar.provider?.score);
// Celo / Arc — lowercase 0x address
const celo = await ak.getKarma('0xcfc0…5b96', { chain: 'celo' });Address formats per chain:
| Chain | Address format |
|---|---|
| solana | base58, 32–44 chars |
| celo, arc | EVM 0x + 40 hex chars (lowercase) |
| stellar | StrKey, 56 chars, starts with G |
The succession, bond, and surety methods take chain as an explicit first argument (see the method table below). The history and feedback endpoints are Solana-only today.
Quick start — Celo ERC-8004 lookup
import { createAgentKarmaClient } from '@agentkarma/sdk';
const ak = createAgentKarmaClient();
const agent = await ak.getCeloAgent(9058);
console.log(agent.owner); // 0x…
console.log(agent.registration?.name); // declared name from the agent registration JSON
console.log(agent.reputation?.average); // mean of unrevoked feedback valuesEnrichment blocks (server ≥ 2026-09, SDK ≥ 0.3.0)
getKarma responses carry optional, additive blocks that turn a thin declared score into an auditable picture. They are omitted when empty or when the read fails; the core score shape never changes.
| Key | What it holds |
|---|---|
| registry | ERC-8004 agents this wallet owns on the chain: name, description, declared services, explorer links |
| declared | The v0.2 metadata rubric: score and 12 per-dimension pass/fail results |
| feedback | ERC-8004 feedback aggregate + newest records from AgentKarma's mirror (source, asOf disclose lag) |
| discovery | x402 endpoints discovered for this wallet (read-only; AgentKarma never calls them) |
| rankScore | Evidence-weighted rank used on Explore (declared evidence ×0.7) |
| explain | Deterministic plain-language sentences summarizing all of the above — hand these straight to an LLM |
const snap = await ak.getKarma('0x558e…9d12', { chain: 'celo' });
for (const line of snap.explain ?? []) console.log('•', line);
// • Provider score 100 (Excellent), declared; no payment receipts on record, …
// • Owns 1 ERC-8004 agent on celo: "Toppa".
// • 581 ERC-8004 feedback records from 490 distinct clients, average 96.7.Trust-gated execution
The evaluateTrust helper is a pure function over a snapshot. No network. No side effects. Always returns { allowed, reasons, observed }.
import { createAgentKarmaClient, evaluateTrust } from '@agentkarma/sdk';
const ak = createAgentKarmaClient();
async function shouldExecute(agentWallet: string) {
const snap = await ak.getKarma(agentWallet);
const decision = evaluateTrust(snap, {
face: 'provider',
minScore: 60,
requireReceiptBacked: true, // require Tier 1 signal present
acceptedConfidenceBadges: ['receipt-backed', 'behavior-inferred'],
minTxCount: 5,
rejectAutonomyLabels: ['agent-like'], // example: human-operated only
});
if (!decision.allowed) {
console.warn('rejected:', decision.reasons);
return false;
}
return true;
}Partner integration pattern
AgentKarma is non-routing. The SDK answers questions about reputation; it does not execute service calls or payments on your behalf. A partner (e.g. a service marketplace, x402 facilitator, agent orchestrator) preflights AgentKarma before performing its own action:
import { createAgentKarmaClient, evaluateTrust, AgentKarmaError } from '@agentkarma/sdk';
const ak = createAgentKarmaClient();
async function payAgentForService(agentWallet: string, amount: number) {
let snap;
try {
snap = await ak.getKarma(agentWallet);
} catch (err) {
// Hard fail-open or fail-closed? Your call. Fail-closed example:
if (err instanceof AgentKarmaError) {
throw new Error('Trust check failed: ' + err.message);
}
throw err;
}
const decision = evaluateTrust(snap, {
minScore: 70,
requireReceiptBacked: true,
minTxCount: 10,
});
if (!decision.allowed) {
throw new Error(`Agent ${agentWallet} did not pass trust check: ${decision.reasons.join('; ')}`);
}
// Your own payment / service call goes here. AgentKarma never proxies it.
return await yourServiceCall(agentWallet, amount);
}Submitting consumer feedback (Solana)
Feedback submission is wallet-agnostic: the SDK builds the message, you sign it externally, the SDK posts the signature.
import { createAgentKarmaClient, buildFeedbackMessage } from '@agentkarma/sdk';
const ak = createAgentKarmaClient();
// 1. Build the canonical message
const { message, timestamp } = buildFeedbackMessage({
rating: 'delivered',
txSignature: 'YourSolanaTxSignature',
});
// 2. Sign with your wallet (any Solana wallet adapter, web3.js, etc.)
const signature = await yourWallet.signMessage(new TextEncoder().encode(message));
const signatureBase58 = base58Encode(signature);
// 3. Submit
await ak.submitFeedback({
agentWallet: 'AgentWalletAddress…',
rating: 'delivered',
txSignature: 'YourSolanaTxSignature',
signature: signatureBase58,
message,
});The server enforces a 5-minute freshness window on the embedded timestamp.
Configuration
const ak = createAgentKarmaClient({
baseUrl: 'https://agentkarma.io', // default
timeout: 10_000, // default ms
headers: { 'X-Partner': 'YourApp' },
userAgent: 'YourApp/1.0',
fetch: customFetch, // optional override
});Each method accepts per-call options:
await ak.getKarma(wallet, {
face: 'provider', // 'provider' | 'consumer' | 'both' (default)
chain: 'stellar', // 'solana' (default) | 'celo' | 'stellar' | 'arc'
signal: abortController.signal, // request-level abort
timeout: 3000, // overrides client default for this call
headers: { 'X-Request-Id': 'abc' },
});Errors
Every error is an AgentKarmaError subclass:
| Class | When |
|---|---|
| AgentKarmaValidationError | Local argument check failed |
| AgentKarmaNotFoundError | Server returned 404 |
| AgentKarmaRateLimitError | Server returned 429 (with retryAfter in seconds) |
| AgentKarmaTimeoutError | Request deadline exceeded |
| AgentKarmaAbortError | Caller's own signal aborted the request |
| AgentKarmaNetworkError | fetch() threw before getting a response |
| AgentKarmaMalformedResponseError | 2xx response body didn't match expected shape |
| AgentKarmaServerError | Other non-2xx response |
import { AgentKarmaError } from '@agentkarma/sdk';
try {
await ak.getKarma(wallet);
} catch (err) {
if (err instanceof AgentKarmaError) {
console.error(`status=${err.status} response=`, err.response);
}
}Public methods
| Method | Endpoint |
|---|---|
| getKarma(wallet, { face?, chain?, … }) | GET /api/v2/score/{wallet}?face={face} — all chains, chain defaults 'solana' |
| getProviderKarma(wallet) | shortcut for provider face only |
| getConsumerKarma(wallet) | shortcut for consumer face only |
| getCeloAgent(agentId) | GET /api/v2/celo/{agentId} |
| searchAgents(query, { limit? }) | GET /api/search?q={query} |
| getAgentHistory(wallet, { limit?, offset? }) | GET /api/agent/{wallet}/history — Solana-only |
| getFeedbackSummary(wallet) | GET /api/feedback?agent={wallet} — Solana-only |
| getSuccessionStatus(chain, wallet) | GET /api/v2/succession/{chain}/{wallet} — all chains |
| getBondStatus(chain, wallet) | GET /api/v2/bond/{chain}/{wallet} — all chains |
| getSuretyKarma(chain, wallet) | GET /api/v2/bond/{chain}/{wallet} (.surety) — all chains |
| submitFeedback(input) | POST /api/feedback — Solana-only |
MCP server & tool catalog
Expose AgentKarma's read surface to any MCP client (Claude Desktop, Cursor, Continue, …).
Turnkey server — run over stdio. The agentkarma-mcp bin ships inside
@agentkarma/sdk and uses the optional @modelcontextprotocol/sdk peer, so the
zero-install one-liner names both packages:
npx -p @agentkarma/sdk -p @modelcontextprotocol/sdk agentkarma-mcp
# point at a different host:
AGENTKARMA_BASE_URL=https://staging.agentkarma.io \
npx -p @agentkarma/sdk -p @modelcontextprotocol/sdk agentkarma-mcpOr install once, then the bin resolves locally:
npm i @agentkarma/sdk @modelcontextprotocol/sdk
npx agentkarma-mcpEmbed the server in your own process:
import { createAgentKarmaMcpServer } from '@agentkarma/sdk/mcp';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const server = createAgentKarmaMcpServer(); // backed by the public API
await server.connect(new StdioServerTransport());@agentkarma/sdk/mcp requires the optional peer dependency @modelcontextprotocol/sdk
(install it only if you use the server). The core client and the tool catalog stay
dependency-free.
Framework-agnostic catalog — the same nine read tools as plain JSON-Schema descriptors you can mount on any host, or run directly:
import { createAgentKarmaClient } from '@agentkarma/sdk';
import { agentKarmaTools, runAgentKarmaTool } from '@agentkarma/sdk/tools';
const ak = createAgentKarmaClient();
agentKarmaTools.map((t) => t.name);
// get_karma, get_celo_agent, search_agents, get_agent_history,
// get_feedback_summary, get_succession, get_bond, get_surety, check_trust
const result = await runAgentKarmaTool(ak, 'check_trust', {
wallet: 'AgentWallet…',
min_score: 60,
require_receipt_backed: true,
});Every tool is read-only, idempotent, and requires no keys. The one write
(submitFeedback) is intentionally excluded, so an MCP server built from this
catalog needs no signer.
Non-routing guarantee
AgentKarma is a reputation primitive. This SDK is read-only by design. It never:
- proxies API calls or x402 payments
- signs transactions on your behalf
- holds private keys
- ratelimits or queues your traffic
You always make your own service calls. AgentKarma just answers the trust question.
License
MIT
