> ## Documentation Index
> Fetch the complete documentation index at: https://docs.proofrail.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# CrewAI

> Govern CrewAI workflows with task-level instrumentation

# CrewAI

The CrewAI adapter wraps a Crew so every task execution is recorded through ProofRail. Both native callback hooks and `execute_task` monkey-patching are supported, depending on your CrewAI version.

## Install

```bash theme={null}
pip install "proofrail[crewai] @ git+https://github.com/TOAAiV/proofrail"
```

This installs `crewai` if not already present.

<Note>
  Supported CrewAI versions: **1.10.x - 2.0.x**. Install with a CrewAI version in this range; the version constraint is pinned in `sdk/pyproject.toml`.
</Note>

## Quick start

```python theme={null}
import asyncio
import proofrail
from proofrail.crewai import govern

from crewai import Agent, Task, Crew

proofrail.init(api_key="prail_...")

# Build your crew as usual
researcher = Agent(role="Researcher", ...)
writer = Agent(role="Writer", ...)

research_task = Task(description="Research the topic", agent=researcher)
write_task = Task(description="Write the report", agent=writer)

crew = Crew(agents=[researcher, writer], tasks=[research_task, write_task])

# Wrap with govern()
governed = govern(crew, chain_name="research-crew")

# Use governed exactly like the original crew
result = await governed.kickoff_async(inputs={"topic": "AI safety"})
```

`governed` has the same interface as the underlying Crew. `kickoff_async` is preferred; `kickoff` (synchronous) works but raises if called from inside a running event loop.

## How it works

The adapter tries two strategies depending on what your CrewAI version exposes:

**Strategy A: Native callbacks** (CrewAI ≥ 0.28)
If your Crew has `task_callback` or `before_task_callback` attributes, the adapter wraps the existing values and inserts governance recording without breaking your callbacks.

**Strategy B: Monkey-patch `Agent.execute_task`** (older CrewAI)
For each agent in the crew, the instance-level `execute_task` method is replaced with a wrapper that fires governance events around the original call. Patches are removed in a `finally` block, so the crew is always restored to its original state after the run.

You don't have to choose. The adapter detects and uses whichever works.

## What gets recorded

For each task execution:

* A `task_execution` event when the task starts, with the task description and expected output as payload
* A `task_result` event when the task completes, with the task's output
* A `task_error` event if the task raises, with the exception details

`agent_name` in each event is the agent's role label (e.g., "Researcher", "Writer").

## Important limitation: deny can't halt mid-task

CrewAI's architecture has a real constraint that affects deny decisions. CrewAI executes tasks synchronously in a way that doesn't expose a pre-execution hook the adapter could use to block. ProofRail records task events **after** each task completes — which means:

**A `deny` decision cannot prevent a task from executing.** It surfaces as an `ActionDeniedError` that halts the next stage of the workflow, not the task itself.

This is different from LangGraph and MCP, where deny can stop execution at the exact point of the violation. For CrewAI:

* **`allow` and `allow_with_flag` work normally** — task runs, event recorded, workflow continues
* **`deny` records the violation and raises after the task completes** — the task already ran, but subsequent tasks are halted
* **`require_approval` may behave unexpectedly** because the approval gate triggers after the task already completed

If you need strict pre-execution governance on CrewAI tasks, two options:

1. **Use `proofrail.Chain` manually inside your task callbacks** — call `record_agent_action` before invoking any tool, getting a real pre-execution check
2. **Wait for native CrewAI middleware support** — this is on CrewAI's roadmap and we'll update the adapter when it lands

For audit purposes (recording what happened), the CrewAI adapter is complete. For strict prevention, it's better suited to workflows where most decisions are `allow` and deny is a rare exception caught for post-hoc review.

## Policy enforcement caveat

Given the limitation above, error handling looks like:

```python theme={null}
from proofrail.exceptions import ActionDeniedError

try:
    result = await governed.kickoff_async(inputs={"topic": "AI safety"})
except ActionDeniedError as exc:
    print(f"Workflow halted after task: {exc.policy_name}")
    print(f"Reason: {exc.condition}")
    # Note: the task that triggered the deny has already executed
    # Subsequent tasks did NOT run
```

The audit trail will show the denied task's `task_execution` and `task_result` events. The `ActionDeniedError` records WHY it was denied. But the side effects of that task — emails sent, records created — already happened.

This is documented; it's not a bug. CrewAI's architecture requires either accepting post-hoc governance or moving the governance check into your task implementations.

## Configuring the chain

```python theme={null}
governed = govern(
    crew,
    chain_name="customer-onboarding-crew",
    metadata={
        "department": "platform",
        "version": "1.2",
        "environment": "production",
    },
)
```

`chain_name` appears in your dashboard. `metadata` is arbitrary key/value pairs attached to every chain run.

## Sync invocation

```python theme={null}
result = governed.kickoff(inputs={"topic": "AI safety"})
```

Raises `RuntimeError` if called from inside a running event loop. In that case use `await governed.kickoff_async(...)`.

## Edge cases

**Hierarchical processes.** CrewAI's hierarchical process (where a manager agent delegates to others) works with the adapter. Each delegated task becomes a separate `task_execution` event.

**Tools used by agents.** If an agent uses CrewAI tools, those tool calls are NOT separately recorded by the CrewAI adapter — only the task-level events are. To record individual tool calls, you'd need to instrument them yourself.

**Custom agent classes.** If you've subclassed `Agent` with a custom `execute_task`, Strategy B's monkey-patch still works — it captures whatever you've defined. Strategy A's native callback approach is independent of `execute_task` implementation.

**Tasks with `human_input=True`.** CrewAI's built-in human-in-the-loop mechanism is separate from ProofRail's approval gate. Both can coexist; CrewAI's handles intra-task input, ProofRail's handles policy-driven approvals.

## When NOT to use this adapter

If your use case requires hard pre-execution prevention (a financial transaction that must NEVER execute without approval), CrewAI's architecture makes this difficult to enforce at the framework level. Consider:

* Adding the check inside your task's tool calls (so the agent can't even initiate the dangerous action)
* Using a different orchestration framework where pre-execution hooks are exposed
* Using ProofRail's framework-agnostic `Chain` directly, controlling governance points precisely

For most CrewAI workflows — research, content generation, data analysis — post-execution governance is sufficient. The audit trail is complete; only strict prevention is constrained.

## Where to go next

<CardGroup cols={2}>
  <Card title="LangGraph adapter" icon="diagram-project" href="/frameworks/langgraph">
    For pre-execution governance with full control.
  </Card>

  <Card title="MCP adapter" icon="plug" href="/frameworks/mcp">
    Govern tool calls at the MCP protocol level.
  </Card>

  <Card title="Manual chain instrumentation" icon="code" href="/quickstart">
    Use `proofrail.Chain` directly for precise governance control.
  </Card>

  <Card title="Policies" icon="shield" href="/concepts/policies">
    How decisions get made on the events the adapter records.
  </Card>
</CardGroup>
