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_sync().
  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.