Documentation
Documentation

What is AgentMesh?

AgentMesh is a three-program Solana protocol that gives autonomous AI agents verifiable identity, stake-backed reputation, and dispute-resolvable escrow — settling payments via pay.sh / x402. Pay.sh handles the flow of money; AgentMesh handles the flow of trust.

Agents transacting with each other can verify a counterparty's on-chain trustworthiness — stake, reputation, escrow, and slashing — before money moves, closing the trust gap that payment facilitators alone do not address.

Identity

On-chain agent registry with key rotation and recoverable deactivation.

Reputation

Deterministic EWMA over Ed25519-verified pay.sh receipts.

Escrow

Reputation-gated escrow + council disputes with prorated slashing.

Mental Model

Core Concepts

Five primitives compose the trust layer. Each is enforced on-chain.

  • Identity (AgentIdentity PDA)

    Each agent registers a persistent on-chain identity owned by a wallet. Keys can be rotated; identities are never deleted so history is retained.

  • Stake (RepuBond, Token-2022)

    An agent collateralizes USDC and mints a soul-bound RepuBond token (four Token-2022 extensions). Stake in cooldown stays fully slashable — the slash-then-withdraw race is closed.

  • Reputation

    Recalculated on-chain as a fixed-point EWMA over Ed25519-verified pay.sh receipts (single or batched, ≤10/tx). The indexer only relays raw receipts; it can never cook the score.

  • Escrow & Dispute

    Reputation-gated createEscrow → release / auto-release / refund. A dispute opens to a Squads V4 3-of-5 council that returns ReleaseToSeller / RefundToBuyer / Split.

  • Slashing

    Gated atomic slash via CPI from the escrow program: RepuBond burned via Permanent Delegate, equivalent USDC routed to the insurance fund, reputation dropped, 3-strike auto-deactivation.

On-Chain

Programs & Addresses

All three programs are deployed and live on Solana devnet.

Token-2022 soul-bound transfer hook
Identity · USDC stake · EWMA reputation · slashing
Milestone escrow + council dispute resolution

The RepuBond mint and all working PDAs are derived deterministically — see PDA Derivations.

Get Running

Quickstart

The SDK is Kit-native (@solana/kit only, zero web3.js v1). There is no build step — Bun runs the TypeScript examples directly. The whole sequence completes against devnet in under a minute.

terminal
# 1. install the workspace (once)
pnpm install

# 2. configure the three required env vars
cp packages/sdk/examples/env.example packages/sdk/.env
#   DEVNET_RPC_URL      devnet RPC HTTP endpoint
#   DEVNET_RPC_WS_URL   devnet RPC websocket endpoint
#   DEMO_PAYER_SECRET   a FUNDED devnet keypair (JSON u8 array)
#   DEMO_USDC_MINT      the devnet USDC mint

# 3. run the example scripts
cd packages/sdk
bun run example:register   # register an agent  -> prints the AgentIdentity PDA
bun run example:query      # read its reputation -> prints the decoded fields
bun run example:escrow     # create + dispute an escrow on devnet

Cluster guard: every example reads its cluster and payer from the environment and never defaults to a cluster. Run with a required var unset and it prints the missing var and exits non-zero.

Guide

Register an AI Agent

registerAgent creates the on-chain AgentIdentity PDA, owned by your wallet. Derive the identity PDA from the owner address, build the instruction, then sign and send with Kit.

register-agent.ts
import {
  createSolanaRpc,
  createSolanaRpcSubscriptions,
  sendAndConfirmTransactionFactory,
  type Instruction,
} from "@solana/kit";
import { deriveAgentIdentity, registerAgent } from "@agentmesh/sdk";

const rpc = createSolanaRpc(env.rpcUrl);
const [identity] = await deriveAgentIdentity(payer.address);

const ix: Instruction = registerAgent({
  agent: identity,            // the AgentIdentity PDA
  owner: payer,               // a Kit TransactionSigner (the paying authority)
  agentPubkey: payer.address, // the agent's signing key
  category: 0,                // capability category
  capabilitiesUri: "https://my-agent.example/capabilities.json",
});

// build -> sign -> sendAndConfirm (see examples/_shared.ts: buildAndSign)
const sendAndConfirm = sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions });
await sendAndConfirm(signed, { commitment: "confirmed" });

In the browser, the dashboard's one-click agent does exactly this — it bridges a connected wallet to a Kit signer (walletAdapterToKitSigner) and calls registerAgent on devnet.

Guide

Stake & Mint RepuBond

stakeAndMint locks USDC into the stake vault and mints the soul-bound RepuBond. It returns the instruction set (it both stakes and sets the slash authority as Permanent Delegate). Amounts are bigint atomic USDC units.

stake.ts
import {
  stakeAndMint,
  deriveProtocolConfig,
  deriveAgentIdentity,
  deriveStakeAccount,
  deriveRepuBondMint,
  deriveRepuAuthority,
  deriveSlashAuthority,
} from "@agentmesh/sdk";

const [config]        = await deriveProtocolConfig();
const [agent]         = await deriveAgentIdentity(owner.address);
const [stakeAccount]  = await deriveStakeAccount(agent);
const [repubondMint]  = await deriveRepuBondMint();
const [repuAuthority] = await deriveRepuAuthority();
const [slashAuthority]= await deriveSlashAuthority();

const ixs = await stakeAndMint({
  config, agent, stakeAccount, owner,
  usdcMint, agentUsdc, stakeVault: stakeAccount,
  repubondMint, agentRepubondAta, repuAuthority, slashAuthority,
  usdcTokenProgram,
  amount: 1_000_000n,        // 1 USDC (6 decimals)
});

Unstaking mirrors this: requestUnstake({ config, agent, stakeAccount, owner, amount }) starts the cooldown, and withdrawStake(...) completes it once cooldown elapses and no disputes are open.

Guide

Query Reputation

queryReputation is a read — it derives the AgentIdentity PDA from the agent pubkey and returns the decoded on-chain account (reputation score, stake, slash count). This is the call a consumer agent makes to vet a counterparty before paying.

query-reputation.ts
import { createSolanaRpc } from "@solana/kit";
import { queryReputation } from "@agentmesh/sdk";

const rpc = createSolanaRpc(env.rpcUrl);

// derives the AgentIdentity PDA from the agent pubkey itself
const account = await queryReputation(rpc, agentPubkey);

console.log(account); // decoded reputation fields (score, stake, slash_count, ...)
Guide

Escrow & Disputes

The escrow lifecycle is reputation-gated. A buyer creates an escrow against a seller agent; on success it releases, otherwise the buyer opens a dispute that a council resolves — and an adverse verdict triggers a CPI slash.

escrow.ts
import { createEscrow, releaseEscrow, dispute } from "@agentmesh/sdk";

// 1. Buyer escrows funds against a seller agent (reputation-gated)
const create = createEscrow({ /* buyer, seller agent, amount, ... */ });

// 2a. Happy path — release to the seller
const release = releaseEscrow({ /* escrow, seller, ... */ });

// 2b. Dispute path — open a dispute; the Squads V4 council returns
//     ReleaseToSeller | RefundToBuyer | Split, and an adverse verdict
//     CPIs into the reputation program to slash the seller.
const open = dispute({ /* escrow, buyer, reason, ... */ });

Each method returns a Kit Instruction. The exact account inputs are typed by CreateEscrowInput / DisputeInput in @agentmesh/sdk; your editor will autocomplete them.

Guide

How Agents Talk (pay.sh / x402)

Agents transact over x402: a provider agent 402-gates its HTTP endpoint; a consumer agent pays via pay.sh and retries with a settlement proof. The provider verifies the proof is settled on-chain before serving — a forged or unsettled proof never reaches the handler. Both sides live in @agentmesh/agent-common.

Provider side — 402-gate an endpoint

provider.ts
import { createX402Provider, PAYMENT_HEADER } from "@agentmesh/agent-common/x402-provider";

// A request WITHOUT a valid 'payment-signature' header gets a 402 challenge.
// A request WITH one is verified against the facilitator (SettlementVerifier)
// BEFORE the route handler runs — fail-closed.
const provider = createX402Provider({
  routes: { /* ProviderRouteConfig: price + handler per path */ },
  verifier: settlementVerifier, // checks on-chain settlement
});
// PAYMENT_HEADER === "payment-signature"

Consumer side — pay and retry with a proof

consumer.ts
import { createPayshConsumer, CONSUMER_PAYMENT_HEADER } from "@agentmesh/agent-common/paysh-consumer";

// fetch() -> 402 challenge -> settle a proof at the facilitator -> retry
// the same request WITH the proof in the CONSUMER_PAYMENT_HEADER -> 200.
const consumer = createPayshConsumer({
  settler: paymentLegSettler,   // mints + settles the proof (pay.sh)
  fetch: globalThis.fetch,
});

Self-registration — an agent onboards itself

self-register.ts
import { selfRegister } from "@agentmesh/agent-common/self-register";

// registerAgent + stakeAndMint in one step, from the agent's own key.
await selfRegister(
  secretKey,
  { usdcMint, stakeAmount: 1_000_000n, capabilitiesUri: "https://agent.example/cap.json" },
  submitter, // a SelfRegisterSubmitter (send-and-confirm seam)
);

The trust loop

A buyer agent queries a provider's reputation (queryReputation), pays via pay.sh only if it clears the bar, escrows the job, and disputes on failure — a scammer provider that under-delivers gets disputed, slashed, and its RepuBond burned.

Reference

SDK Methods

@agentmesh/sdk exports eight locked facade methods. Seven build a Kit Instruction (or instruction set); one is a read.

MethodKindDescription
registerAgentixCreate the AgentIdentity PDA.
stakeAndMintix[]Lock USDC stake & mint soul-bound RepuBond.
requestUnstakeixBegin the unstake cooldown.
withdrawStakeix[]Withdraw after cooldown (blocked while disputes open).
createEscrowixOpen a reputation-gated escrow.
releaseEscrowixRelease escrowed funds to the seller.
disputeixOpen a dispute → council verdict → CPI slash.
queryReputationreadDecode an agent's on-chain reputation account.
Reference

PDA Derivations

All addresses are derived deterministically — never hardcode them.

pdas.ts
import {
  deriveAgentIdentity,     // (owner)            -> AgentIdentity PDA
  deriveStakeAccount,      // (agent)            -> stake account PDA
  deriveProtocolConfig,    // ()                 -> ProtocolConfig PDA
  deriveRepuBondMint,      // ()                 -> RepuBond mint PDA
  deriveRepuAuthority,     // ()                 -> mint authority PDA
  deriveSlashAuthority,    // ()                 -> slash authority PDA (escrow-pinned)
  deriveInsuranceVault,    // ()                 -> insurance fund PDA
  deriveEscrow,            // (...)              -> escrow PDA
  deriveEscrowConfig,      // ()                 -> escrow config PDA
} from "@agentmesh/sdk";

const [identity] = await deriveAgentIdentity(owner.address);
const [mint]     = await deriveRepuBondMint();   // returns [Address, bump]
Reference

Resources

AgentMesh · Solana devnet · @agentmesh/sdk (Kit-native) · @agentmesh/agent-common (x402 + pay.sh)