Aroha
Get started

Get started

Pick the path that matches what you already run. Each one ends with a test that proves the refusals work, because a permission layer you have not seen refuse something is not one you can rely on.

TypeScript
npm install @aroha-sdk/core @aroha-sdk/credentials
Python
pip install "aroha>=2"

A

Wrap an MCP server

Anyone using MCP tools in an assistant such as Claude Code, Cursor or Claude Desktop.

A config change, no code.

Path A in the integration guide

mcp-guard sits between the assistant and the server. Matching tools are refused, wait for a person to approve, or stop after a set number of calls. List the server's real tool names first: rules match names, and every server names things its own way.

Your MCP client's config
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@aroha-sdk/mcp-guard",
               "--name",  "github",
               "--block", "*delete*,*remove*",
               "--gate",  "merge_*,push_*,create_*,update_*",
               "--limit", "*:50",
               "--",
               "npx", "-y", "@modelcontextprotocol/server-github"]
    }
  }
}

B

Verify mandates in a handler

Teams whose API or tool server agents call.

About 10 lines.

Path B in the integration guide

One call checks the agent's proof over this exact request, the chain back to the customer, every limit on every link, and charges the running total, all or nothing.

TypeScript
import { verifyHttpSpendRequest, enrolledDid, httpRevocationCheck } from "@aroha-sdk/credentials";

const r = await verifyHttpSpendRequest(req.headers["aroha-mandate"], {
  audience: "https://invoices.example.com",
  method: req.method, url: req.url, body: rawBody,      // the exact bytes received
  expectedRoot: await enrolledDid(enrollments, customerId),
  isRevoked: httpRevocationCheck(REGISTRY_URL),
  amountUsd: invoice.amountUsd, currency: "USD",
  nonces, ledger,
});
if (!r.ok) return reply(res, r.status, { error: r.code });   // nothing was charged
Python
from aroha import verify_http_spend_request
from aroha.enrollment import enrolled_did

r = verify_http_spend_request(
    request.headers.get("aroha-mandate"),
    audience="https://api.example.com", method=request.method, url=url, body=raw,
    expected_root=enrolled_did(ENROLLMENTS, invoice["customerId"]),
    is_revoked=None,                      # or a revocation check; you must choose
    amount_usd=invoice["amountUsd"], currency="USD",
    nonces=NONCES, ledger=LEDGER,
)
if not r.ok:
    return JSONResponse({"error": r.code}, status_code=r.status)

C

Issue and present a mandate

Agents acting on a person's behalf.

About 15 lines.

Quickstart

A person grants, an agent narrows, and the narrower token travels with every call the next agent makes.

TypeScript
import { generateKeyPair, generateDid } from "@aroha-sdk/core";
import { issueIntentMandate, attenuateToPayment } from "@aroha-sdk/credentials";

// The person grants their assistant $500 for airline fares, for one hour.
const intent = await issueIntentMandate(
  personDid, assistantDid,
  { spendLimitUsd: 500, merchantCategory: "4511" },
  person.privateKey, 3_600_000,
);

// The assistant passes $300 of it to the flight agent: any agent can narrow what it was given.
const payment = await attenuateToPayment(
  intent, flightAgentDid,
  { spendLimitUsd: 300, merchantCategory: "4511" },
  assistant.privateKey,
);

D

Run the Aroha runtime

A person's own assistant, on their own machine.

Not yet released.

What the runtime supports

The runtime is a desktop assistant built on Aroha: tools are denied until a person allows them, approvals become signed, revocable permissions, and actions leave receipts. It is not yet available as a download. Paths A to C work today.

E

Connect a hosted assistant

People using ChatGPT and dots, Claude and Duet, or Muse.

Coming soon.

The remote connector

These assistants add tools through remote MCP connectors. Aroha's connector, @aroha-sdk/mcp-server in remote mode, is published: each person gets their own key, sensitive actions ask first, and every approval becomes a signed limit. It has not yet been tested with each assistant, so we do not call it supported. Setup guides will follow the tests.

SDKs

Every SDK checks the same test vectors. Feature matrix.

LanguagePackagePublishedStatus
TypeScript@aroha-sdk/credentials2.0.0Reference implementation
Pythonaroha2.1.0Beta
Gosdks/goNoPartial, not yet published
Javacom.aroha-labs:aroha-sdkNoPartial, not yet published

Using a coding agent?

Point it at the integration guide. It is written as an Agent Skill: the agent picks a path, applies it, and proves each refusal before it reports done. For everything else, llms.txt indexes the documentation as plain text.

Stuck? Ask in GitHub Discussions or email contact@aroha-labs.com.