TS
TypeScript SDK
v1.2.0 · MIT License · ESM · Node.js 22+
The reference implementation of the Aroha Protocol. 20 packages covering every protocol primitive — transport, identity, orchestration, credentials, settlement, reputation, and more.
Installation
Install only what you need. Every package is independently versioned.
# Minimum — agent transport + identity npm install @aroha-sdk/core # Full stack — add orchestration, auth, and payment npm install @aroha-sdk/core @aroha-sdk/orchestrator @aroha-sdk/credentials @aroha-sdk/settlement # Personal agent bridges npm install @aroha-sdk/hermes-bridge # Hermes Agent / ZeroClaw (MCP stdio) npm install @aroha-sdk/openclaw-bridge # OpenClaw skills npm install @aroha-sdk/composio-bridge # TrustClaw / Composio actions # Framework bridges npm install @aroha-sdk/langchain-bridge # LangChain + AutoGen npm install @aroha-sdk/mcp-bridge # Model Context Protocol npm install @aroha-sdk/a2a-bridge # Google A2A
All packages are pure ESM. Set
"type": "module" in your package.json or use .mjs extensions.npm audit warnings: The SDK's optional dependencies (AutoGen, CrewAI bridges) may trigger moderate severity audit warnings on transitive sub-dependencies. These do not affect the core runtime. Run
npm audit --omit=optional to see only warnings relevant to packages you install directly.Using the TypeScript source directly? Each package must be compiled before it can be imported. From the monorepo root:
npm run build --workspaces, or per-package: cd packages/aroha-core && npm run build. The compiled output lands in dist/ — the main field in each package.json points there.Core: ArohaServer & ArohaClient
@aroha-sdk/core is the only required package. It handles the full protocol stack: HTTP transport, Ed25519 envelope signing/verification, nonce replay protection, and WebSocket streaming.
Minimal agent (devMode)
import { ArohaServer, generateDid, generateKeyPair, MapNonceStore } from "@aroha-sdk/core";
// Generate a keypair and DID (persist these in production)
const { privateKey, publicKey } = await generateKeyPair();
const myDID = generateDid(publicKey);
const server = new ArohaServer({
agentDID: myDID,
didDocument: {
"@context": ["https://www.w3.org/ns/did/v1"],
id: myDID,
verificationMethod: [{
id: `${myDID}#key-1`,
type: "Ed25519VerificationKey2020",
controller: myDID,
publicKeyMultibase: Buffer.from(publicKey).toString("base64"),
}],
},
port: 3000,
devMode: true, // skip crypto in development (NODE_ENV=development required)
onMessage: async (envelope, respond, stream) => {
console.log("Received:", envelope.type, "from", envelope.from);
// respond() sends a synchronous reply
// stream() pushes events over WebSocket
},
resolvePublicKey: async (did) => {
// Return the sender's Ed25519 public key bytes, or null if unknown
return null;
},
});
await server.start();
console.log(`Agent ${myDID} listening on port 3000`);Production server (full crypto)
import { ArohaServer, generateDid, generateKeyPair } from "@aroha-sdk/core";
import { createRbacMiddleware } from "@aroha-sdk/credentials";
const { privateKey, publicKey } = await generateKeyPair();
const myDID = generateDid(publicKey);
const server = new ArohaServer({
agentDID: myDID,
didDocument: { /* ... */ },
port: 3000,
resolvePublicKey: async (did) => {
// Fetch from your registry or cache
const doc = await fetch(`https://aroha-registry.aroha-labs.workers.dev/dids/${did}`);
const { publicKey } = await doc.json();
return Buffer.from(publicKey, "base64");
},
middleware: [
// RBAC: require the caller to hold a valid SpendingMandate
createRbacMiddleware({ requiredTrustLevel: 2 }),
],
clockToleranceMs: 5000, // allow 5s clock skew across regions
maxBodyBytes: 1_048_576, // reject payloads > 1 MiB
minClientVersion: "1.0", // reject old client versions
onMessage: async (envelope, respond) => {
if (envelope.type === "ArohaRequest") {
const { capability, params } = envelope.body;
// handle capability...
respond(await buildEnvelope("ArohaResponse", myDID, envelope.from,
{ capability, result: { ok: true } },
envelope.correlationId, privateKey));
}
},
});
await server.start();ArohaClient — calling other agents
import { ArohaClient, buildEnvelope, newCorrelationId } from "@aroha-sdk/core";
const client = new ArohaClient();
const envelope = await buildEnvelope(
"ArohaRequest",
myDID, // from
"did:aroha:travel-agent", // to
{ capability: "search-flights", params: { from: "JFK", to: "LHR", date: "2026-08-01" } },
newCorrelationId(), // unique ID for this request
privateKey // signs the envelope
);
const response = await client.send("http://travel-agent.example.com", envelope);
if (response?.type === "ArohaResponse") {
console.log(response.body.result); // { flights: [...] }
}
if (!response) {
// Agent returned 202 — response will arrive via WebSocket stream
}Identity & DIDs
import { generateKeyPair, generateDid, buildWebDID } from "@aroha-sdk/core";
// did:aroha: (self-sovereign, content-addressed)
const { privateKey, publicKey } = await generateKeyPair();
const did = generateDid(publicKey);
// → "did:aroha:base58encodedPublicKey"
// did:aroha-web: (domain-anchored, like did:web:)
const webDID = buildWebDID("myco.ai", ["agents", "travel"]);
// → "did:aroha-web:myco.ai:agents:travel"
// Serve the DID document at /.well-known/aroha/agents/travel/did.json
// The ArohaServer does this automatically when webDIDDocument is set.Envelopes & Message Types
Every Aroha message is a signed envelope. The 16 built-in types map to the full protocol lifecycle:
ArohaRequestOrchestrator → Provider: invoke a capability
ArohaResponseProvider → Orchestrator: synchronous result
ArohaStreamProvider → Orchestrator: progress update (WebSocket)
ArohaErrorEither direction: structured error with retryable flag
ArohaReserveSaga step 1: reserve resources, return commitToken
ArohaCommitSaga step 2: commit reserved resources
ArohaCancelSaga compensation: release reserved resources
ArohaHandoffTransfer control to another agent
ArohaDiscoveryQuery the registry for agents with a capability
ArohaCapabilityOfferAgent advertises a capability to another
ArohaAuditTrailAppend-only audit event (hash-chained)
ArohaReputationUpdateSignal: satisfied / neutral / dissatisfied
import { buildEnvelope, newCorrelationId } from "@aroha-sdk/core";
// All envelope fields are set automatically:
// id → urn:uuid:<random>
// created → now
// expires → now + 5 min (default)
// nonce → random 16 bytes (base64url)
// proof → Ed25519 signature over canonical JSON
const env = await buildEnvelope(
"ArohaReserve", // type
orchestratorDID, // from
providerDID, // to
{
capability: "book-flight",
params: { from: "JFK", to: "LHR" },
budgetUsd: 500,
},
newCorrelationId(), // correlationId (ties Reserve→Commit→Cancel)
orchestratorPrivateKey
);SagaEngine & Orchestration
The @aroha-sdk/orchestrator package provides atomic multi-agent transactions using the saga pattern: Reserve → Commit → Cancel (LIFO compensation on failure).
import { SagaEngine, AgentSelector } from "@aroha-sdk/orchestrator";
import { ArohaClient } from "@aroha-sdk/core";
const saga = new SagaEngine({ client, orchestratorDID, privateKey });
// Each step is: reserve with one agent, then another, then commit all or cancel all
const result = await saga.run([
{
agentDID: "did:aroha:flight-agent",
endpoint: "http://flights.example.com",
capability: "reserve-flight",
params: { from: "JFK", to: "LHR", date: "2026-08-01" },
budgetUsd: 300,
},
{
agentDID: "did:aroha:hotel-agent",
endpoint: "http://hotels.example.com",
capability: "reserve-hotel",
params: { city: "London", nights: 3 },
budgetUsd: 200,
},
]);
// If hotels.example.com fails: flight reservation is automatically cancelled
// result.status → "committed" | "compensated"
// result.steps[n].commitToken → use for billing reconciliationAgentSelector — pick the best agent
import { AgentSelector } from "@aroha-sdk/orchestrator";
import { ArohaHttpRegistry } from "@aroha-sdk/registry";
const registry = new ArohaHttpRegistry("https://aroha-registry.aroha-labs.workers.dev");
const selector = new AgentSelector(registry);
// Discovers agents with "search-flights", ranks by reputation + latency + price
const best = await selector.select("search-flights", {
maxLatencyMs: 2000,
maxPriceUsd: 0.01,
minTrustLevel: 2,
});
console.log(best.manifest.did, best.endpoint);Credentials & RBAC
import {
issueSpendingMandate,
verifySpendingMandate,
createRbacMiddleware,
attenuateMandate,
} from "@aroha-sdk/credentials";
// Issue a mandate: user authorises the orchestrator to spend up to $500
const mandate = await issueSpendingMandate({
grantor: userDID,
grantee: orchestratorDID,
constraints: {
spendLimitUsd: 500,
allowedCapabilities: ["search-flights", "reserve-flight", "book-hotel"],
expiresAt: new Date(Date.now() + 3600_000), // 1 hour
},
privateKey: userPrivateKey,
});
// Attenuate: orchestrator delegates a sub-mandate to a sub-agent (≤ original limits)
const subMandate = await attenuateMandate(mandate, {
grantee: flightAgentDID,
spendLimitUsd: 300, // must be ≤ 500
allowedCapabilities: ["reserve-flight"],
}, orchestratorPrivateKey);
// On the server — enforce via middleware
const server = new ArohaServer({
middleware: [
createRbacMiddleware({
requiredTrustLevel: 2,
verifyMandate: true, // envelope must carry a valid SpendingMandate
}),
],
// ...
});Settlement
import { createSettlementMiddleware, StripeSettlementBackend } from "@aroha-sdk/settlement";
// Stripe backend — charges the mandate holder's card after Commit
const settlement = new StripeSettlementBackend({
secretKey: process.env.STRIPE_SECRET_KEY!,
});
const server = new ArohaServer({
middleware: [
createSettlementMiddleware({ backend: settlement }),
],
// ...
});
// Available backends:
// NullSettlementBackend — free tier / dev
// QuotaSettlementBackend — internal credit system
// StripeSettlementBackend — card charges
// EscrowSettlementBackend — hold funds until CommitAgent Registry
import { InMemoryRegistry, ArohaHttpRegistry } from "@aroha-sdk/registry";
// Development: in-process registry
const registry = new InMemoryRegistry();
registry.register({
did: myDID,
endpoint: "http://localhost:3000",
capabilities: [
{ id: "search-flights", description: "Search available flights" },
],
});
// Production: federated HTTP registry
const registry = new ArohaHttpRegistry("https://aroha-registry.aroha-labs.workers.dev");
// Discover agents
const agents = await registry.find({ capability: "search-flights" });
// → [{ manifest: { did, capabilities }, endpoint }]Framework Bridges
Hermes Agent & ZeroClaw (MCP stdio)
// hermes.config.json (or zeroclaw config.toml)
{
"mcpServers": {
"aroha-travel": {
"command": "npx",
"args": [
"@aroha-sdk/hermes-bridge",
"--endpoint", "http://travel-agent.example.com",
"--agent-did", "did:aroha:travel-agent"
]
}
}
}OpenClaw
// openclaw-plugin.mjs
import { createArohaOpenClawPlugin } from "@aroha-sdk/openclaw-bridge";
import { generateKeyPair, generateDid } from "@aroha-sdk/core";
const { privateKey, publicKey } = await generateKeyPair();
const myDID = generateDid(publicKey);
export default createArohaOpenClawPlugin("aroha-travel", [
{
capabilityId: "search-flights",
endpoint: "http://travel-agent.example.com",
agentDID: "did:aroha:travel-agent",
callerDID: myDID,
callerPrivateKey: privateKey,
description: "Search and book flights via Aroha travel agent",
parameters: {
from: { type: "string", description: "Origin IATA code (e.g. JFK)" },
to: { type: "string", description: "Destination IATA code (e.g. LHR)" },
date: { type: "string", description: "Departure date YYYY-MM-DD" },
},
},
]);Composio / TrustClaw
import { Composio } from "composio-core";
import { registerArohaCapabilities } from "@aroha-sdk/composio-bridge";
import { generateKeyPair, generateDid } from "@aroha-sdk/core";
const composio = new Composio({ apiKey: process.env.COMPOSIO_API_KEY });
const { privateKey, publicKey } = await generateKeyPair();
const myDID = generateDid(publicKey);
await registerArohaCapabilities(composio, [
{
endpoint: "http://travel-agent.example.com",
agentDID: "did:aroha:travel-agent",
capabilityId: "search-flights",
description: "Search for available flights",
callerDID: myDID,
callerPrivateKey: privateKey,
parameters: {
from: { type: "string", description: "Origin IATA code" },
to: { type: "string", description: "Destination IATA code" },
},
required: ["from", "to"],
},
]);
// Now TrustClaw, Claude+Composio, GPT-4+Composio can all call thisLangChain / AutoGen
import { arohaCapabilityToLangChainTool, arohaCapabilityToOpenAITool } from "@aroha-sdk/langchain-bridge";
// LangChain tool
const flightTool = arohaCapabilityToLangChainTool("search-flights", {
endpoint: "http://travel-agent.example.com",
agentDID: "did:aroha:travel-agent",
callerDID: myDID,
callerPrivateKey: privateKey,
description: "Search available flights between airports",
});
// AutoGen / OpenAI function tool
const flightFn = arohaCapabilityToOpenAITool("search-flights", { /* same opts */ });
// Pass to your LangChain agent as a normal tool
const agent = initializeAgentExecutorWithOptions([flightTool], llm, { agentType: "openai-functions" });All Packages
@aroha-sdk/coreTransport (HTTP + WS), Ed25519, envelopes, nonce registry, DID generation
@aroha-sdk/orchestratorSagaEngine (Reserve→Commit→Cancel), AgentSelector, CSN negotiation
@aroha-sdk/credentialsSpendingMandate issue/attenuation/verify, RBAC middleware
@aroha-sdk/registryAgent discovery — InMemoryRegistry, ArohaHttpRegistry, on-chain registry
@aroha-sdk/settlementPayment backends: Null, Quota, Stripe, Escrow
@aroha-sdk/reputationBayesian Beta engine, Thompson Sampling, satisfaction signals
@aroha-sdk/policyCapability allow/deny rules, prompt injection defense
@aroha-sdk/cacheSemantic request caching keyed by capability + params hash
@aroha-sdk/telemetryOpenTelemetry traces + W3C Trace Context headers
@aroha-sdk/commerceB2B agreements, subscription billing, audit trail
@aroha-sdk/preferencesUser preference profiles, soft-scoring for agent selection
@aroha-sdk/trusted-meshVPC/mTLS trusted mesh — bypass Ed25519 for internal calls
@aroha-sdk/mcp-bridgeMCP tool definitions ↔ Aroha capabilities (bidirectional)
@aroha-sdk/a2a-bridgeGoogle A2A message format ↔ Aroha envelopes
@aroha-sdk/langchain-bridgeLangChain tools ↔ Aroha capabilities, AutoGen + Semantic Kernel
@aroha-sdk/hermes-bridgeHermes Agent + ZeroClaw: MCP stdio server wrapping Aroha agents
@aroha-sdk/openclaw-bridgeOpenClaw skills ↔ Aroha capabilities (bidirectional)
@aroha-sdk/composio-bridgeComposio custom actions for TrustClaw, Claude, GPT-4, Gemini
@aroha-sdk/micro5-line dev server: createMicroAgent({ capabilities, port })
@aroha-sdk/clinpx @aroha-sdk/cli scaffold — generate a typed Aroha agent project