Install
crewai 1.13 to 2.0. 1.13 is the release that added started_event_id and normalized token usage, both of which the adapter relies on to pair events and report tokens.
Instrument
instrument() registers a listener on CrewAI’s module-level event bus and subscribes one handler per event class. Nothing about your crew, agents, tasks, or tools changes.
What gets recorded
A task emits nothing on purpose. A CrewAI task is a subset of the agent execution that runs it, so emitting both would double every row and render them as siblings. The task id and name ride along on the agent’s own events instead.
Memory and knowledge operations are recorded as tools, named for the surface they hit, so they appear next to your real tools where you can compare their latency.
On a hierarchical crew, the nesting is what makes the trace readable:
delegate_work_to_coworker tool event, not on the manager directly, so the adapter follows that link. Without it every agent comes out a sibling of every other and the delegation structure is lost.
Example
analyst span closes, the writer span opens, and both sit inside one crew span.
Name your spans
agent_id comes from Agent(role=...), which is what makes it a readable dashboard facet.
agent_id is a low-cardinality column. A role containing a run id or timestamp degrades it for every query anyone runs. If a role looks like an id, the adapter refuses it and puts the real value in a payload field instead.
Control the session
Resolved in this order, first match winning:instrument("crewai", session_id=...)- The enclosing
failproofai_sdk.session()scope - A generated
uuid4().hex, once per crew or flow
Options
session_id is the only option this adapter reads. Prompts and completions are always recorded, truncated to the payload budget.
Human in the loop
CrewAI has two human-in-the-loop surfaces, and both are recorded as the same four events.@human_feedback on a flow method goes through CrewAI’s event bus: the runtime emits an event before it blocks on a person and another after the answer.
Task(human_input=True) does not. It calls input() inside CrewAI’s own input provider and emits no event of any kind, so the adapter wraps that provider directly — without it the entire human wait was invisible and billed as active agent time.
Either way you get:
agent_pause to agent_resume is the only pair that feeds paused time. Without it, a ten-minute human wait is billed as ten minutes of active agent time.
CrewAI sets no correlation id on either human-feedback event, so the adapter pairs them on the flow and method name, falling back to the most recently opened pause. That is sound because a console prompt blocks. If you build a concurrent feedback provider, set
request_id on both events.Because the
Task(human_input=True) path is a wrapper around CrewAI’s input provider rather than an event subscription, it is restored on uninstrument() and re-raises whatever input() raises, KeyboardInterrupt included, unchanged.Common problems
The agent filter has thousands of entries
The agent filter has thousands of entries
A
role contains a UUID, timestamp, or per-run suffix. Use a stable human role and put the run-specific id in the task description instead.A test reads zero events, but the dashboard shows them
A test reads zero events, but the dashboard shows them
The event bus is asynchronous, and This is a property of CrewAI, not of the SDK.
kickoff() returns before the last handlers run. Drain it first:A session shows as ongoing forever
A session shows as ongoing forever
agent_end force-closes open pauses but not tools or models, so a run that dies inside a tool call leaves that span open. Normal teardown closes whatever is still open and marks it incomplete. Only a SIGKILL leaves it hanging, because nothing can run.Nothing is recorded
Nothing is recorded
Check in this order:
instrument() ran before kickoff(); there is a with failproofai_sdk.session(): around it; crewai is 1.13 or newer; FAILPROOFAI_SDK_STRICT=1 set, so a degraded hook raises instead of being swallowed.Next
How it works
Pairs, ids, session lifecycle, and delivery.
Read a trace
Follow causality through the session you just captured.
Other frameworks
LangGraph, LlamaIndex, Pydantic AI, and custom agents.

