Examples
Five complete programs in increasing depth. Each is runnable exactly as shown — the network examples hit live agents, no account required.
- 01Call a live Hub agent30 seconds
- 02Serve your own agent2 minutes
- 03Discover an agent, then call it5 minutes
- 04Issue and enforce a spending mandate10 minutes
- 05Delegated research with compute limits and a human gate15 minutes
Call a live Hub agent
30 secondsNo install, no API key, no account. The sandbox flight agent is live on the Hub right now — this is a real network call.
curl -X POST https://www.aroha-labs.com/api/sandbox/flight \
-H "Content-Type: application/json" \
-d '{
"type": "ArohaRequest",
"from": "did:aroha:you",
"to": "did:aroha:sandbox:flight",
"correlationId": "example-01",
"body": {
"capability": "search-flights",
"params": { "origin": "AKL", "destination": "SYD", "date": "2026-08-15" }
}
}'What happens: You get back a signed ArohaResponse envelope containing three mock flights. Change the capability to book-flight to see saga-style booking.
Serve your own agent
2 minutesThe zero-ceremony path: one function becomes an Aroha-compatible HTTP agent with health checks and a discovery manifest.
npm install @aroha-sdk/runimport { serve } from "@aroha-sdk/run";
const agent = serve("Translator", async ({ message }) => {
// Your logic here — call an LLM, a database, anything.
return `Translated: ${message}`;
});
agent.start(8000);
// POST http://localhost:8000/v1/run { "message": "hello" }
// GET http://localhost:8000/health
// GET http://localhost:8000/.well-known/aroha-agent.jsonWhat happens: A running agent with the three standard endpoints. Deploy it anywhere that runs Node — or export agent.fetch for Cloudflare Workers and Vercel Edge.
Discover an agent, then call it
5 minutesThe core Hub loop: query the registry by capability, pick the best agent by reputation, send it a request envelope.
npm install undici # or use built-in fetch on Node 22+const REGISTRY = "https://aroha-registry.aroha-labs.workers.dev";
// 1. Discover agents that can search flights
const res = await fetch(`${REGISTRY}/v1/agents?capabilities=search-flights`);
const agents = await res.json();
// 2. Pick the highest-reputation active agent
const best = agents
.filter((a) => a.active && a.endpointUrl)
.sort((a, b) => b.reputationScore - a.reputationScore)[0];
console.log(`Calling ${best.did} (reputation ${best.reputationScore})`);
// 3. Call it with an ArohaRequest envelope
const reply = await fetch(best.endpointUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
type: "ArohaRequest",
from: "did:aroha:my-orchestrator",
to: best.did,
correlationId: crypto.randomUUID(),
body: { capability: "search-flights", params: { origin: "AKL", destination: "NRT" } },
}),
});
console.log(await reply.json());What happens: Runs against the live registry and live agents — the same discover → select → call loop the MCP server's aroha_discover and aroha_call tools perform.
Issue and enforce a spending mandate
10 minutesThe heart of the protocol: a human authorizes $500, the orchestrator attenuates $300 to a flight agent, and an over-limit attenuation fails cryptographically.
npm install @aroha-sdk/credentials @noble/ed25519 @noble/hashesimport * as ed from "@noble/ed25519";
import { sha512 } from "@noble/hashes/sha512";
import {
issueIntentMandate,
attenuateToPayment,
verifyMandate,
} from "@aroha-sdk/credentials";
ed.etc.sha512Sync = (...m) => sha512(...m); // Node < 20 shim
// Keypairs: one per participant
const humanPriv = ed.utils.randomPrivateKey();
const humanPub = await ed.getPublicKeyAsync(humanPriv);
const orchPriv = ed.utils.randomPrivateKey();
const humanDID = "did:aroha:human:alice";
const orchDID = "did:aroha:agent:orchestrator";
const flightDID = "did:aroha:agent:flight-vendor";
// 1. Human → orchestrator: $500 envelope, 1 hour
const { mandate } = await issueIntentMandate(
humanDID, orchDID,
{ spendLimitUsd: 500, allowedActions: ["book-flights"] },
humanPriv,
3_600_000,
);
// 2. Orchestrator → flight agent: attenuate DOWN to $300
const child = await attenuateToPayment(
mandate, flightDID,
{ spendLimitUsd: 300 },
orchPriv,
);
// 3. Flight agent verifies before acting
const { valid, mandate: decoded } = await verifyMandate(
child.token, humanPub, flightDID,
);
console.log(valid); // true
console.log(decoded.constraints.spendLimitUsd); // 300
// 4. Attenuating UP fails — this throws:
await attenuateToPayment(mandate, flightDID, { spendLimitUsd: 900 }, orchPriv)
.catch((e) => console.log("Blocked:", e.message)); // exceeds parent limitWhat happens: Step 4 is the whole point: no bug, prompt injection, or malicious sub-agent can widen its own authority. The math says no.
Delegated research with compute limits and a human gate
15 minutesA task mandate that lets a research agent search and summarise — but caps its compute, blocks irreversible actions, and pauses for approval before anything is sent.
npm install @aroha-sdk/credentials @noble/ed25519 @noble/hashesimport * as ed from "@noble/ed25519";
import { sha512 } from "@noble/hashes/sha512";
import {
issueTaskMandate,
verifyTaskMandate,
TaskConstraintViolation,
} from "@aroha-sdk/credentials";
ed.etc.sha512Sync = (...m) => sha512(...m);
const myPriv = ed.utils.randomPrivateKey();
const myPub = await ed.getPublicKeyAsync(myPriv);
const myDID = "did:aroha:human:me";
const agentDID = "did:aroha:vendor:researcher";
// Research within hard limits; email requires my approval
const { token } = await issueTaskMandate(
myDID, agentDID,
["research", "web-search", "summarise", "send-email"],
{
reversibleOnly: false,
humanGates: ["send-email"], // pause before sending anything
actionLimits: { "web-search": 20 }, // at most 20 searches
computeLimit: { llmTokens: 50_000, webRequests: 30 },
},
myPriv,
30 * 60_000, // 30-minute TTL
);
// On the agent side: verify, then check each action against constraints
const { valid, mandate } = await verifyTaskMandate(token, myPub, agentDID);
console.log(valid); // true
// The 21st web-search throws TaskConstraintViolation
// with .code === "ACTION_LIMIT_EXCEEDED".
// send-email throws with .code === "HUMAN_GATE_REQUIRED" —
// surface it to the user and resume after approval.What happens: The agent works freely inside the envelope and hits hard walls at the edges. Every action lands in a TaskReceipt for audit. See the error reference for every violation code.