Add execution receipts to a CrewAI crew: every task leaves a record anyone can check.

Two routes, both honest. Route 1: install crewai-zambo from PyPI and attach its ZamboCrewListener to your crew; every task event publishes a verifiable receipt at a public URL, captured when the task finishes. Route 2: serve the crew's tool calls through the Zambo MCP and close the run with workflow_close, binding every step receipt into one sealed record with a single root. Either way the record is made at execution time, outside the agents' control, and anyone can verify it by recompute.

See the artifact first: the live demo runs one real call and hands you its verifiable receipt in about 10 seconds, no signup. That receipt is the same object your crew's tasks will publish.

Published October 13, 2026. Package facts checked against PyPI (crewai-zambo 0.1.6) and the package source the same day.

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.
The claim stays narrow on purpose. A receipt proves the saved result was not changed since it was saved. It does not prove the crew's output was correct or the plan was good. It settles what ran, what it was given, and what came back, in a form the crew's owner does not have to take on trust.

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.