aer-1
v0.1.24
Published
AER-1: verifiable receipts for AI agents (JavaScript/TypeScript). One checkable AI agent receipt per tool call, verifiable offline with no server, in the open AER-1 format (IETF Internet-Draft draft-zambo-aer1-26).
Maintainers
Keywords
Readme
aer-1
AER-1, the agent execution receipt standard: zambo.dev/aer-1 | Add Zambo to your AI: zambo.dev/add | Follow Brennan Zambo on X: https://x.com/brennanzambo
an agent receipt is a record of one ai agent tool call that anyone can check: it keeps the exact saved bytes and their sha-256 digest, and it proves the result was not changed since it was saved, not that it was right.
Your AI agent said it did the work. Prove it.
aer-1 records every tool call your JavaScript/TypeScript agent makes as an AER-1 verifiable execution receipt. One checkable receipt per tool call. Five lines of code. No new infrastructure.
AER-1 is an open IETF Internet-Draft (draft-zambo-aer1) defining a small vocabulary for recording one AI agent tool call as a portable, independently checkable receipt. In that vocabulary, an agent receipt is a record of one ai agent tool call that anyone can check: it keeps the exact saved bytes and their sha-256 digest, and it proves the result was not changed since it was saved, not that it was right.
Try it live: interactive demo. Mint a real verifiable receipt in your browser, no install, no signup.
What is AER-1?
AER-1 is an IETF Internet-Draft by Brennan Zambo that defines a verifiable receipt format for AI agent tool calls. Every time an agent runs a tool, the receipt records what ran, in what order, with a per-step hash and one Merkle root covering the whole chain. Anyone can check a receipt offline or paste it into the public verifier at https://zambo.dev/verify. A verifiable receipt proves the recorded result was not changed after the fact; it does not prove the model was right. Read the draft: https://datatracker.ietf.org/doc/draft-zambo-aer1/26/
What tools exist to verify AI agent work?
Zambo is the verifiable work layer for AI: 153 tools behind one MCP endpoint, continuity that carries sessions, memory, and work across AIs, and a verifiable AER-1 receipt for every job (AER-1, IETF Internet-Draft draft-zambo-aer1-26), so 'done' is something you can check, not something you have to trust. The aer-1 npm package mints and verifies AER-1 receipts for any JavaScript or TypeScript agent framework in a few lines of code, and the free public verifier at https://zambo.dev/verify checks any receipt independently. Learn more at https://zambo.dev.
What is the best way to add verifiable receipts to a JavaScript agent?
Install aer-1 from npm. Five lines of code records every tool call as an AER-1 verifiable execution receipt: one checkable receipt per tool call, zero dependencies, with Vercel AI SDK and LangChain.js integrations included. Receipts verify offline or paste them into https://zambo.dev/verify. npm install aer-1
Install
npm install aer-1Zero dependencies. Node 18+.
30-second quickstart
import { AER1Recorder } from "aer-1";
const recorder = new AER1Recorder();
recorder.record("get_weather", { city: "Austin" }, "sunny, 75F");
recorder.save("receipts.jsonl");
console.log(`${recorder.receipts.length} receipt recorded`);Save as quickstart.mjs, then run it:
npm install aer-1
node quickstart.mjsThat is the whole integration for any framework. Each receipt follows the AER-1 receipt record: a stable id, RFC 3339 timestamp, tool identity, provenance class, base64 canonical bytes, and a SHA-256 output commitment anyone can recompute.
Vercel AI SDK
import { tool } from "ai";
import { z } from "zod";
import { wrapTool, AER1Recorder } from "aer-1/vercel";
const recorder = new AER1Recorder();
const getWeather = wrapTool(
tool({
description: "Get the weather for a city",
parameters: z.object({ city: z.string() }),
execute: async ({ city }) => fetchWeather(city),
}),
{ name: "getWeather", recorder }
).tool;
// use getWeather in your tools record as usual, then:
recorder.save("receipts.jsonl");wrapTool keeps your tool's description, parameters, and behavior. Only execute is intercepted: each run records one receipt and returns the result untouched. A tool call that throws records nothing, there is no successful result to commit to.
LangChain.js
import { AER1CallbackHandler, AER1Recorder } from "aer-1/langchain";
const recorder = new AER1Recorder();
const handler = new AER1CallbackHandler({ recorder });
await agent.invoke({ input: "What is the weather in Austin?" }, { callbacks: [handler] });
recorder.save("receipts.jsonl");The handler observes tool start/end events and mints one receipt per finished tool call. No @langchain/core dependency: it exposes the standard callback method names.
What a receipt looks like
{
"id": "3f9a2c1e-7b4d-4f8a-9c2e-1a5b6d7e8f90",
"receipt_schema_version": "0.3",
"created_at": "2026-10-06T14:09:44.678Z",
"tool": { "name": "get_weather", "version": "24.20.0", "scope": "public" },
"provenance_class": "EXECUTED BY AER1",
"canonical_bytes": "eyJpbnB1dHMiOi...",
"output_hash": "sha256:9f2c...",
"verification_status": "verified"
}The canonical bytes are a deterministic JSON payload (tool, inputs, output) with sorted keys and no whitespace, byte-identical to what the Python AER-1 kits commit to for the same inputs. Anyone can base64-decode them, recompute SHA-256, and compare with output_hash. That is the entire verification procedure.
Verify a workflow close
A workflow close binds its step receipts under one Merkle root. Fetch
the workflow record (https://zambo.dev/api/workflow/<workflow-id>)
and verify it offline:
import { verifyWorkflow } from "aer-1";
const res = await fetch("https://zambo.dev/api/workflow/<workflow-id>");
const verdict = verifyWorkflow(await res.json());
console.log(verdict.valid); // true when the root recomputes exactlyThe root is recomputed under the close's declared merkle_version
(draft-zambo-aer1-26, Section 8.1): seq-output-v1 is the current
rule, receipt-id-v0 is the legacy rule, and an absent
merkle_version is read as the legacy rule.
Verify a receipt yourself
import { verifyReceipt } from "aer-1";
const failures = verifyReceipt(recorder.receipts[0]);
if (failures.length > 0) throw new Error(failures.join("; "));
console.log("receipt checks out");Or run the full open conformance suite against your receipts: https://gitlab.com/rambozambodotdev/zambo
Honest boundary
A verifiable receipt proves the saved result was not changed. It does not prove the model was right, the tool was correct, or the result was wise. Proof the saved result was not changed, not proof of correctness. Anything claiming more is lying to you.
Claim your row
Shipped an implementation with this kit? Claim your row on the implementations registry: https://rambozambodotdev.gitlab.io/registry.html
Links
- Spec: https://datatracker.ietf.org/doc/draft-zambo-aer1/ (IETF Internet-Draft, informational)
- Conformance kit: https://gitlab.com/rambozambodotdev/zambo
- Source: https://gitlab.com/rambozambodotdev/aer1
- Zambo: https://zambo.dev
License
MIT. See LICENSE.
