EvalLayerTry the demo

Adding commercial guardrails to CrewAI agents

Published 2026-07-27 · EvalLayer

You add commercial guardrails to CrewAI agents by attaching a function guardrail to the task that produces outbound content: the function posts the task output to EvalLayer's /authorize endpoint and returns success with the approved text on allow or rewrite, or failure with the violation detail so the agent revises, while require_approval drafts are queued for a human. Pair it with the same check inside any send tool, and no crew output reaches a customer unchecked.

Why crews amplify commercial risk

CrewAI's model is role-based delegation: a researcher hands to an analyst, the analyst hands to a writer, the writer's output becomes an email, a proposal, a published post. That pipeline shape is the risk. Each agent treats the previous agent's output as ground truth, so one invented claim or over-generous concession early in the crew propagates downstream with growing confidence, and the last task ships it. In a single-agent loop a bad draft is one mistake; in a crew it is a supply chain.

CrewAI knows output quality is the weak point, which is why task guardrails exist: a validation step that runs after a task completes and before its output passes to the next task, with automatic retry when validation fails. The framework supports function-based guardrails (your Python, full control) and LLM-based ones (a judge described in natural language). What ships in the box is the mechanism. The commercial judgment, discount caps, spend authority, forbidden commitment types, approved claims, is the part you supply, and an agent grading its own crew's homework is not a control.

The interception point: a task guardrail on the outbound task

Attach the check where crew output becomes consequential: the task whose result will be sent, published, or executed.

import httpx
from crewai import Task

POLICY = {
    "max_discount_pct": 10,
    "commitment_authority_usd": 2500,
    "forbidden_commitments": ["delivery_date", "indemnification"],
    "approved_claims": ["iso27001_certified"],
    "required_disclaimers": ["pricing_subject_to_change"],
    "blocked_topics": [],
}

def commercial_guardrail(output):
    r = httpx.post(
        "https://api.evallayer.ai/authorize",
        headers={"Authorization": "Bearer " + EVALLAYER_KEY},
        json={"action_type": "send_email", "content": output.raw,
              "context": {"crew": "sales_outreach"}, "policy": POLICY},
        timeout=10,
    )
    data = r.json()

    if data["decision"] == "allow":
        return (True, output.raw)
    if data["decision"] == "rewrite":
        return (True, data["approved_rewrite"])
    if data["decision"] == "require_approval":
        queue_for_human(output.raw, data["authorization_id"])
        return (False, "Exceeds authority, held for human approval: "
                + data["violations"][0]["detail"])
    return (False, "Blocked by commercial policy: "
            + data["violations"][0]["detail"])

outreach_task = Task(
    description="Draft the renewal offer email for the account.",
    agent=writer,
    guardrail=commercial_guardrail,
)

The return contract does the work. Success passes the approved text forward, which means a rewrite is substituted silently and the next task (or the send step) uses the compliant version. Failure sends your message back to the agent and CrewAI retries the task, so the violation detail becomes revision instructions, and the revised output hits the same guardrail again.

For tools that act directly, a send_email tool an agent can invoke mid-task, put the identical /authorize call inside the tool body before the side effect, or block it in a before-tool-call hook. CrewAI's hook surface can stop a tool execution outright; the tool-body check is the version-stable pattern.

Decision handling in crew terms

  • allow: guardrail returns success with the original output; the crew proceeds.
  • rewrite: guardrail returns success with approved_rewrite; downstream tasks and the send step consume the compliant text.
  • require_approval: the draft plus authorization_id go to a human queue, and the guardrail returns failure so nothing sends automatically while review is pending.
  • block: guardrail returns failure with the reason; the agent revises or the crew ends without sending. Log the authorization_id either way.

Latency and placement

Guard the last mile, not the whole pipeline. Research and analysis tasks pass their output along unchecked; only tasks whose output leaves the crew get a guardrail. On those, deterministic policies add milliseconds and semantic checks one to two seconds, trivial next to the minutes a multi-agent crew already spends. The retry loop multiplies checks only when there are violations, which is exactly when you want it to.

What to log

Store every authorization_id with the kickoff ID and task name. Crews are the hardest agent systems to audit after the fact because responsibility is spread across roles; a per-task authorization record collapses that to a single question with a single answer: what did policy say about the thing that actually shipped?

Try it on one crew

Point the guardrail at /demo/authorize first (three free checks per day, no key) or watch the interactive demo catch planted violations. Decision semantics are specified in the authorization guide; policy design covers writing a policy object that matches what your humans are actually allowed to promise.

Frequently asked questions

Function guardrail or LLM guardrail on the task?

Function guardrail. CrewAI's LLM-based guardrails ask a model to judge output against a natural-language description, which reintroduces the problem: a model grading a model, with no policy object and no audit record. A function guardrail calling /authorize gets deterministic checks on the countable rules, one governed semantic pass on the rest, and an authorization_id for every decision.

What happens when the guardrail returns False?

CrewAI feeds your error message back to the agent and retries the task, up to its retry limit. That loop is exactly right for fixable violations: the agent revises with the violation detail in hand, and the revision is re-checked before it goes anywhere. For require_approval cases you queue the draft for a human as well, so a compliant-looking retry cannot slip past the authority limit.

Do I still need the check if only one agent in the crew sends anything?

Gate that one surface, yes, and that is usually enough. The clean pattern is one guardrail on the final outbound task plus the same check inside any send tool an agent can call directly. Research and drafting tasks in the middle of the crew need no gate.

See the authorization layer live

Paste a message, set a policy, get allow / rewrite / require approval / block in seconds.

Try the demo