CrewAI

Gate sensitive CrewAI Assistant actions behind a human approval step. Wrap any tool with a Cheqpoint checkpoint before it executes.

Prerequisites

  • Python environment with crewai installed.
  • Cheqpoint Python SDK.
  • Cheqpoint Connection Key.

Steps

  1. Create a custom tool by inheriting from CrewAI's BaseTool.
  2. In the tool's execution logic, wrap the primary function call with client.request().
  3. Pass the tool's arguments into the details dictionary of the request.
  4. Implement a check on the response status.
  5. If approved, allow the tool to complete its task and return the result to the CrewAI Agent.
  6. If rejected, return a string to the Agent explaining that a human reviewer declined the action, optionally including the decisionNote for context.

Installation

bash
python3 -m pip install cheqpoint crewai crewai-tools

Sample request payload

json
{
  "action": "publish_github_release",
  "summary": "CrewAI release manager agent creating v2.0.1",
  "details": {
    "repo": "org/main-app",
    "tag": "v2.0.1",
    "changelog": "Fixed major security vulnerability."
  },
  "justification": "Security patches verified by CI/CD agent."
}

Sample Cheqpoint response

json
{
  "status": "approved",
  "modifiedDetails": {
    "tag": "v2.0.1-stable"
  },
  "decisionNote": "Approve but append -stable suffix for consistency."
}

Python — request_sync() in a CrewAI tool

python
from cheqpoint import CheqpointClient
from crewai_tools import BaseTool

cheq = CheqpointClient(api_key="cq_live_...")

class PublishReleaseTool(BaseTool):
    name: str = "publish_github_release"
    description: str = "Publish a GitHub release after human approval"

    def _run(self, repo: str, tag: str, changelog: str) -> str:
        result = cheq.request_sync(
            action="publish_github_release",
            summary=f"CrewAI release manager agent creating {tag}",
            details={"repo": repo, "tag": tag, "changelog": changelog},
            justification="Security patches verified by CI/CD agent.",
            timeout_ms=30_000,  # poll up to 30 s
        )
        if result["status"] == "approved":
            effective_tag = (result.get("modifiedDetails") or {}).get("tag", tag)
            return publish_release(repo, effective_tag, changelog)
        return f"Release blocked: {result.get('decisionNote', 'rejected by reviewer')}"

Notes

You have full control over what data is passed into the details object to provide human reviewers with sufficient context.

Tips

Start by routing only high-risk or high-value actions to minimize friction while maintaining oversight.

Get your Connection Key at cheqpoint.co/signup.