Five Packages That Changed How I Build AI Agents
A working tour of the Aroha toolkit, in Python and TypeScript — from a five-line agent to multi-agent webs that can't exceed their authority. Written by the person who built it, bugs included.

Every agent project I've worked on hits the same moment: the demo works. Which means the agent can now do things. Which means you suddenly, urgently care about what it's allowed to do — and you discover that “allowed” isn't a concept anywhere in your stack.
I've spent the last year building a toolkit around that moment. Everything below is MIT-licensed, works without an account, and — this was a rule I set early — has to be useful inside the first five minutes, alone, before any grand protocol vision kicks in. Here's the honest tour.
1. serve() — an agent in five lines
I resent frameworks that make me learn their cosmology before I can answer an HTTP request, so the on-ramp is just a function wrapper.
Python (pip install aroha):
from aroha import serve
@serve(name="echo")
async def handler(message, context):
return {"echo": message}
handler.start(port=8000)TypeScript (npm install @aroha-sdk/run — zero dependencies, deliberately):
import { serve } from "@aroha-sdk/run";
const agent = serve("echo", async ({ message }) => `Echo: ${message}`);
agent.start(8000);
Both give you /v1/run with streaming, sessions, a health check, and a manifest. The TS one runs on Cloudflare Workers and Vercel Edge by exporting agent.fetch. Flip exposeMcp: true and the same agent is an MCP server Claude Desktop can call — which still feels slightly like cheating.
The point isn't the five lines. It's that this same function can later verify mandates and join delegation chains without a rewrite. The on-ramp and the protocol are the same road.
2. mcp-guard — the seatbelt
I wrote a whole post about this one, so the short version: it wraps any MCP server with block/gate/limit rules and an audit log, in one config change, no code. Everything ambiguous fails closed. I built it in a couple of days, mostly out of pieces the other packages already had — and it's quietly become the most-downloaded thing I've shipped, which tells you something about where the actual pain is.
3. Mandates — limits that math enforces
This is the heart of the toolkit, and the idea I'd defend in a bar argument: don't ask an agent to respect a budget. Hand it a signed token it cannot exceed, because everyone downstream verifies the signature, and the rules of the system say a delegated token can only ever get narrower.
import { issueIntentMandate, attenuateToPayment } from "@aroha-sdk/credentials";
// I grant my orchestrator $500
const intent = await issueIntentMandate(
myDid, orchestratorDid,
{ spendLimitUsd: 500, allowedActions: ["book-flights"] },
myPrivateKey, 3_600_000,
);
// It narrows to $300 for the flight agent — fine
await attenuateToPayment(intent, flightAgentDid, { spendLimitUsd: 300 }, orchKey);
// It tries $800 — throws.
// "child spendLimitUsd (800) exceeds parent (500)"Python mirrors the same model with aroha.mandate — issue_intent_mandate, attenuate_to_payment, verify_mandate.

attenuateToPayment takes the whole signed envelope, not the bare mandate. The example in the docs now shows the output of actually running it, because apparently I can't be trusted to write examples from memory either. Nobody can. Run your examples.4. Delegation — the web
The newest one, and the reason I finally believe the multi-agent story. Every orchestration framework can make agent A call agents B, C, and D. None of them answer: what stops C from doing something A never authorized?
import { serveDelegated, registryResolver } from "@aroha-sdk/delegation";
serveDelegated("orchestrator", {
identity: { did: myDid, privateKey: myKey },
trustAnchors: { [aliceDid]: alicePublicKeyB64 },
resolvePublicKey: registryResolver(),
}, async (ctx) => {
ctx.assertCapability("research"); // verified before your code even runs
const search = await ctx.delegate(searcherDid, ctx.message, { allowed: ["web-search"] });
const summary = await ctx.delegate(summariserDid, search.message, { allowed: ["summarise"] });
return summary.message;
}).start(8000);
Each ctx.delegate() extends a signed chain where scope only shrinks and delegation depth counts down — a depth-0 mandate is a dead end, so the agents-spawning-agents runaway is structurally impossible rather than discouraged. Receipts nest all the way back to whoever started the chain, under one correlation ID. My favorite moment building it: the end-to-end demo — three real agents on localhost — caught a response-parsing bug my unit tests missed entirely. The demo now ships in the repo as the proof, warts fixed.
Two caveats, because I'd rather you hear them from me: the delegation runtime is TypeScript-first today (Python can speak the wire format — it's plain JSON — but the ergonomic runtime is on the roadmap, not in the box). And a chain of trustworthy signatures is only as interesting as the agents signing them, which brings me to —
5. The Hub — agents you can actually call
A registry you can query by capability, with live sandbox agents that need no account. This works right now, from your terminal:
curl -X POST https://www.aroha-labs.com/api/sandbox/echo \
-H "Content-Type: application/json" \
-d '{"type":"ArohaRequest","from":"did:aroha:you","to":"did:aroha:sandbox:echo",
"correlationId":"c1","body":{"capability":"echo","params":{"message":"hello"}}}'Full disclosure: the sandbox agents (flights, hotels, weather, search) are mock-data agents I run myself, clearly labeled as such. The registry's job right now is to make the discover-verify-call loop real end to end. Filling it with agents I didn't write is the entire game from here, and I know it.
If you only try one thing
Using an assistant with MCP tools? mcp-guard, tonight, zero code. Building an agent? serve(), then add mandate verification the day your agent grows teeth. Building a fleet? The delegation package is the quarter of engineering you were about to do yourself.
The spec is open (github.com/ArohaLabs/aroha-spec), and I read everything that lands in the repo issues. The one-line thesis, since every post needs one: agents should carry proof of what they're allowed to do — and your infrastructure should check it, because the model's good manners won't.