Guard.verify(...) before each tool call.
What the adapter does
The CrewAI wrapper runs all three gates on each tool call:- Capability - pass
required_capabilities=[...]to the wrapper (or acapabilitiesmap toguard_crew_tools). A call whose needs aren’t a subset of the agent’s grant is blocked. Omit it for content-gate-only checking. - Content - PII detection and policy-specific content rules on the first string argument.
- Budget - pass
cost_cents=...to debit the guard’s budget per call.
"[CERTIOR BLOCKED] {reason}" rather than raising; CrewAI surfaces that as the tool’s output, and the agent’s reasoning loop sees it.
Pattern 1: decorate one tool
certior_tool_wrapper(guard=None, policy="default", tool_name="", *, required_capabilities=None, cost_cents=0) is the full signature. When guard is omitted, the wrapper builds its own Guard(policy=policy). tool_name is what appears in the audit log (defaults to the function’s __name__). required_capabilities turns on the capability gate; cost_cents debits the budget.
Pattern 2: guard every tool in an existing crew
guard_crew_tools(crew, guard, capabilities=None) walks every agent’s tools list and replaces each tool’s function with the guarded wrapper. Tools named in capabilities have the capability gate enforced; the others are content-gate-only. The crew is mutated in place and also returned for chaining.
Raise instead of returning a blocked string
The wrapper returns"[CERTIOR BLOCKED] {reason}" so the agent’s reasoning loop can see it. If you’d rather halt hard on a capability or budget miss, also decorate the underlying function with @guard.wrap(...) - that path raises CertiorBlocked before the body runs:
@guard.wrap above @certior_tool_wrapper, capability + budget is checked first (raising CertiorBlocked on a miss); only if that passes does the inner wrapper run.
See also
- OpenAI guide - same gate via
verify_tool_calls(). - Custom loop - direct
Guard.verify()/@guard.wrap().