Route 1: the crewai-zambo package
The packaged route is a listener. crewai-zambo (on PyPI, version 0.1.6) provides ZamboCrewListener: attach it to the CrewAI listener mechanism supported by your installed CrewAI version, or call on_task_completed from a task completion hook. Each task event is published to the Zambo endpoint (the listener posts the event to https://zambo.dev/mcp; set ZAMBO_API_URL to use a compatible host) and comes back as a public, verifiable receipt at a https://zambo.dev/run/{id} URL.
from crewai_zambo import ZamboCrewListener
listener = ZamboCrewListener()
result = listener.on_task_completed("Summarize this task", "completed")
print(listener.last_receipt_url or result)
The listener prints each receipt URL as tasks finish, keeps every URL in receipt_urls and the most recent in last_receipt_url, and records any publish failure in receipt_errors rather than swallowing it. Two properties matter for trust. Capture happens when the task event fires, not when somebody later exports a log. And the package's own README states the receipt's limit plainly: the receipt describes what the live endpoint recorded and observed; it does not prove an outside outcome that the endpoint did not observe.
Working offline instead? Pass emit_aer1=True and the same listener mints AER-1 receipts locally, with no API calls: every event is recorded on your own machine with the format's core members (id, created_at, tool, provenance class, canonical bytes, output hash). The package also exposes mint_receipt and verify_receipt helpers, so any tool call can be receipted directly and checked by recomputing its SHA-256 locally.
Route 2: direct MCP, no package
If your crew's agents call tools through MCP, you can skip the listener entirely. Point those calls at a receipt-issuing MCP server, Zambo's MCP at zambo.dev/mcp, and every tool call returns its result plus a verifiable receipt, captured server-side at execution. The pattern is the one described in MCP server receipts: the record is made by the layer that ran the call, so the agent never gets to edit its own history.
When the run finishes, call workflow_close. The step receipts from the run bind into a single summary receipt whose children list names every step receipt and whose root digest is computed over them, so the whole job verifies as one sealed record: a step added, dropped, or swapped after the fact breaks the root. Per-task receipts answer "what did this agent do"; the closed record answers "what did the crew do, in full".
What the crew owner gets
- One receipt per task: the task the agent was given and the output that came back, hash-committed at the moment the task completed, each at a public URL a client or auditor can open without your help.
- One root for the whole job: close the run and its step receipts bind into a single sealed record, so the run can be handed over and checked as a set.
- Absences you can see: a task an agent claims but never finished leaves no receipt, and the gap shows in the record instead of being smoothed over by a final summary.
- An acceptance check: the Walk-Away Test: set the crew a countable multi-step job, walk away, and on return read the record before the summary. Claimed steps versus recorded steps is the whole audit.
- Full days covered: a Day Pass ($0.99) keeps every call receipted for 24 hours, and sealed runs keep their page, verify badge, and PDF pack after the free viewing window.
CrewAI execution receipts: FAQ
How do I add execution receipts to a CrewAI crew?
Install the crewai-zambo package from PyPI and attach its ZamboCrewListener to your crew: attach it to the CrewAI listener mechanism supported by your installed CrewAI version, or call on_task_completed from a task completion hook. Each task event is then published as a verifiable receipt at a public https://zambo.dev/run/ URL, and the listener prints each URL and keeps the latest in last_receipt_url. The package-free route: serve the crew's tool calls through a receipt-issuing MCP server such as Zambo's MCP at zambo.dev/mcp, and call workflow_close at the end of the run so the step receipts bind into one sealed record.
Can I verify what each agent in my crew did?
Yes, agent by agent and task by task. Every task completion the listener publishes becomes its own receipt: the task event, the task the agent was given, and the output the endpoint recorded and observed, committed under a SHA-256 hash at the moment the task finished and published at a URL anyone can fetch. Recompute the commitment from the receipt's canonical bytes; a match means the saved record is the record made when the task ran. An agent that claims a task it never finished has no receipt to point to, and that absence is visible in the run's record instead of hidden in a summary.
Do CrewAI task outputs come with proof?
Not by default. CrewAI gives you the outputs its agents produce and its own run logs, and both are records the run itself controls: an output can be retold, trimmed, or regenerated later and nothing in the framework marks the change. Proof appears when the output is captured at execution time by a layer outside the agent's control and committed under a hash: the output bytes saved as recorded, a digest over them, and a public URL where anyone can fetch the record and recompute the digest. That is the record the crewai-zambo listener adds. It proves the saved output is the output that was recorded when the task finished; whether the output was any good remains a judgment the receipt does not make for you.
What does a CrewAI run receipt contain?
One receipt per task event, in the AER-1 format: the task event name, the task the agent was given, the output the endpoint recorded and observed, a timestamp, and the SHA-256 commitments (the canonical bytes and the output hash) that make the record checkable by recompute. The listener collects every receipt URL in receipt_urls and the most recent in last_receipt_url, and publish failures land in receipt_errors instead of vanishing. With emit_aer1=True the package also mints local AER-1 receipts with no API calls, which carry the same core members and pass the same hash-recomputation check offline. AER-1 is an open IETF Internet-Draft, so the format is public text, not a vendor schema.