← Back to DevBytes

Building a Code Review Agent with CrewAI: Complete Guide

Introduction to CrewAI and Code Review Agents

What is CrewAI?

CrewAI is an open-source Python framework designed for orchestrating role-playing, autonomous AI agents. It enables developers to create collaborative teams of agents—called "crews"—where each agent has a specific role, goal, and backstory. These agents can work together, delegate tasks, and communicate with each other to solve complex problems. Think of it as an AI-powered team where each member brings a specialized skill set to the table.

The framework leverages large language models (LLMs) such as GPT-4, Claude, or open-source models via APIs like OpenAI, Anthropic, or local providers such as Ollama. CrewAI handles the orchestration logic—determining which agent acts next, how they share information, and when a task is considered complete.

What is a Code Review Agent?

A Code Review Agent built with CrewAI is an automated system that mimics the human code review process. Instead of a single monolithic reviewer, you assemble a crew of specialized agents—each focused on a different aspect of code quality. One agent might scrutinize code style and readability, another might hunt for security vulnerabilities, while a third analyzes performance implications and algorithmic efficiency.

The agents receive source code as input, apply their specialized knowledge, and produce structured feedback—catching bugs, suggesting improvements, and flagging potential issues before the code reaches production.

Why Automated Code Review Matters

Manual code review is time-consuming, inconsistent, and often becomes a bottleneck in fast-moving development teams. Automated code review agents offer several compelling benefits:

Setting Up Your Environment

Prerequisites

Before building your code review crew, ensure you have the following ready:

Installation

Start by creating a dedicated project directory and a virtual environment. Then install CrewAI along with the necessary dependencies:

# Create project directory and enter it
mkdir code-review-crew
cd code-review-crew

# Create a virtual environment
python -m venv venv

# Activate the virtual environment
# On Linux/macOS:
source venv/bin/activate
# On Windows:
venv\Scripts\activate

# Install CrewAI and dependencies
pip install crewai
pip install crewai[tools]  # Optional: pre-built tools for common tasks

Next, set up your API key as an environment variable. CrewAI will automatically detect it from your environment:

# Set your OpenAI API key (Linux/macOS)
export OPENAI_API_KEY="your-openai-api-key-here"

# Or for Windows (PowerShell)
$env:OPENAI_API_KEY = "your-openai-api-key-here"

# If using Anthropic Claude
export ANTHROPIC_API_KEY="your-anthropic-api-key-here"

# Verify the key is set
echo $OPENAI_API_KEY

You can also store the API key in a .env file in your project root and use Python's dotenv package to load it:

# .env file contents
OPENAI_API_KEY=sk-your-actual-key-here
OPENAI_MODEL_NAME=gpt-4o

Building Your Code Review Crew

Now we'll construct a complete code review crew with three specialized agents. Each agent brings a distinct lens to the review process, and together they produce comprehensive, actionable feedback.

Defining the Agents

Create a new Python file called code_review_crew.py. We'll define three agents: a Senior Code Reviewer, a Security Analyst, and a Performance Auditor. Each agent receives a clear role, goal, and backstory that shapes its behavior:

# code_review_crew.py

from crewai import Agent, Task, Crew, Process
import os

# --- Agent 1: Senior Code Reviewer ---
senior_reviewer = Agent(
    role="Senior Code Reviewer",
    goal=(
        "Thoroughly review the provided source code for correctness, "
        "readability, maintainability, and adherence to best practices. "
        "Identify logical errors, code smells, and architectural concerns."
    ),
    backstory=(
        "You are a veteran software engineer with 15 years of experience "
        "across multiple languages and frameworks. You've mentored dozens "
        "of junior developers and have a keen eye for subtle bugs. Your "
        "reviews are known for being meticulous yet constructive. You "
        "always provide specific line references and concrete improvement "
        "suggestions rather than vague criticism."
    ),
    verbose=True,
    allow_delegation=False,
    llm="gpt-4o",  # Uses OPENAI_API_KEY from environment
)

# --- Agent 2: Security Analyst ---
security_analyst = Agent(
    role="Application Security Analyst",
    goal=(
        "Scan the provided source code for security vulnerabilities, "
        "including injection risks, improper input validation, exposed "
        "secrets, insecure dependencies, and authentication flaws. "
        "Prioritize findings by severity."
    ),
    backstory=(
        "You are a certified application security specialist (think OWASP "
        "contributor and former penetration tester). You instinctively look "
        "for the OWASP Top 10 vulnerabilities in every code review. You "
        "explain each vulnerability clearly, describe the potential attack "
        "vector, and provide remediation code snippets. You never approve "
        "code that handles user input without proper sanitization."
    ),
    verbose=True,
    allow_delegation=False,
    llm="gpt-4o",
)

# --- Agent 3: Performance Auditor ---
performance_auditor = Agent(
    role="Performance & Scalability Auditor",
    goal=(
        "Analyze the source code for performance bottlenecks, inefficient "
        "algorithms, memory leaks, unnecessary allocations, and scalability "
        "concerns. Suggest optimizations with complexity analysis."
    ),
    backstory=(
        "You are a backend architect who specializes in high-traffic systems. "
        "You've optimized systems serving millions of requests per second. "
        "You can spot O(n²) algorithms hiding behind clean abstractions and "
        "you understand caching strategies, database query patterns, and "
        "asynchronous processing deeply. You always back your findings with "
        "Big-O complexity comparisons."
    ),
    verbose=True,
    allow_delegation=False,
    llm="gpt-4o",
)

Notice how each agent has a tightly scoped responsibility. The Senior Reviewer focuses on correctness and style, the Security Analyst hunts vulnerabilities, and the Performance Auditor looks at algorithmic efficiency. This separation of concerns is key to getting high-quality, non-overlapping feedback.

Creating Tasks

Tasks define the concrete work each agent performs. Each task is linked to a specific agent and includes a detailed description of what to analyze, plus the expected output format. Add these task definitions to your file:

# --- Task 1: General Code Review ---
general_review_task = Task(
    description=(
        "Conduct a comprehensive code review of the following source code. "
        "Examine:\n"
        "- Code structure and organization\n"
        "- Variable naming and readability\n"
        "- Error handling completeness\n"
        "- Adherence to DRY and SOLID principles\n"
        "- Potential logical errors or off-by-one mistakes\n"
        "- Testability concerns\n\n"
        "Provide your findings organized by file and line number. For each "
        "issue, include: severity (CRITICAL / HIGH / MEDIUM / LOW), the "
        "specific line(s) affected, a clear explanation, and a suggested fix.\n\n"
        "Source code to review:\n"
        "{source_code}"
    ),
    agent=senior_reviewer,
    expected_output=(
        "A structured code review report with sections for each file "
        "reviewed. Each finding includes severity, line numbers, explanation, "
        "and remediation. End with an overall summary and a recommendation "
        "on whether the code is ready for production."
    ),
)

# --- Task 2: Security Audit ---
security_audit_task = Task(
    description=(
        "Perform a thorough security audit of the following source code. "
        "Specifically look for:\n"
        "- SQL/LDAP/command injection vulnerabilities\n"
        "- Cross-site scripting (XSS) vectors\n"
        "- Hardcoded secrets, API keys, or credentials\n"
        "- Missing input validation or sanitization\n"
        "- Insecure cryptographic usage\n"
        "- Path traversal and file access issues\n"
        "- Authentication/authorization bypass risks\n\n"
        "For each vulnerability found, provide: severity using CVSS-inspired "
        "rating (CRITICAL / HIGH / MEDIUM / LOW), the vulnerable code snippet, "
        "an explanation of the attack vector, and a secure code alternative.\n\n"
        "Source code to audit:\n"
        "{source_code}"
    ),
    agent=security_analyst,
    expected_output=(
        "A security audit report listing each vulnerability with severity, "
        "vulnerable code excerpt, attack description, and secure remediation "
        "code. Vulnerabilities sorted by severity descending. Include a "
        "'Security Verdict' at the end: PASS or FAIL with justification."
    ),
)

# --- Task 3: Performance Review ---
performance_review_task = Task(
    description=(
        "Analyze the following source code for performance and scalability "
        "issues. Evaluate:\n"
        "- Algorithmic complexity (Big-O analysis) of key functions\n"
        "- Unnecessary loops, repeated computations, or redundant I/O\n"
        "- Memory allocation patterns and potential leaks\n"
        "- Database query efficiency (N+1 queries, missing indices)\n"
        "- Opportunities for caching or lazy evaluation\n"
        "- Concurrency and parallelism potential\n\n"
        "For each finding, include: the current complexity, a proposed "
        "optimization with its improved complexity, and an estimated impact "
        "(e.g., 'reduces response time from O(n²) to O(n) for large inputs').\n\n"
        "Source code to analyze:\n"
        "{source_code}"
    ),
    agent=performance_auditor,
    expected_output=(
        "A performance audit report with each bottleneck described using "
        "Big-O notation. Before/after complexity comparisons for each "
        "suggested optimization. A final section recommending priority "
        "optimizations ranked by estimated impact."
    ),
)

The {source_code} placeholder in each task description is a template variable. When you run the crew, you'll inject the actual source code into this variable. This allows you to reuse the same crew definition across different code reviews.

Assembling the Crew

Now bring the agents and tasks together into a single Crew object. The crew orchestrates execution—by default, tasks run sequentially, and each agent receives the output from previous tasks as context (unless you configure otherwise):

# --- Assemble the Code Review Crew ---
code_review_crew = Crew(
    agents=[senior_reviewer, security_analyst, performance_auditor],
    tasks=[general_review_task, security_audit_task, performance_review_task],
    process=Process.sequential,  # Tasks execute one after another
    verbose=True,  # Set to True to see agent reasoning in console
    memory=True,   # Agents retain context across tasks
)

The Process.sequential setting ensures tasks run in order: general review first, then security audit, then performance analysis. The memory=True flag allows agents to see the outputs of previous tasks, which can be useful if the security analyst wants to reference findings from the general reviewer.

Running the Code Review Agent

With the crew defined, you need a way to feed source code into it and collect results. Create a runner script that loads source files, invokes the crew, and saves the output:

# run_review.py

import os
from code_review_crew import code_review_crew

def load_source_code(file_paths):
    """
    Reads multiple source files and combines them into a single string
    with file headers for context.
    """
    combined = ""
    for path in file_paths:
        if not os.path.exists(path):
            print(f"Warning: File not found: {path}")
            continue
        with open(path, "r", encoding="utf-8") as f:
            content = f.read()
        combined += f"\n# --- File: {path} ---\n{content}\n"
    return combined

def run_code_review(source_code_str):
    """
    Executes the code review crew on the provided source code string.
    Returns the final crew output.
    """
    inputs = {
        "source_code": source_code_str
    }
    
    print("🚀 Starting code review crew...")
    print(f"   Agents: Senior Reviewer, Security Analyst, Performance Auditor")
    print(f"   Code length: {len(source_code_str)} characters")
    print("-" * 60)
    
    result = code_review_crew.kickoff(inputs=inputs)
    
    print("-" * 60)
    print("✅ Code review complete!")
    return result

if __name__ == "__main__":
    # Example: review specific files in your project
    files_to_review = [
        "src/auth/login.py",
        "src/database/connection.py",
        "src/api/handlers.py",
    ]
    
    # Alternatively, review a single file
    # files_to_review = ["src/main.py"]
    
    print("📂 Loading source files...")
    source_code = load_source_code(files_to_review)
    
    if not source_code.strip():
        print("❌ No source code loaded. Check file paths.")
        exit(1)
    
    review_results = run_code_review(source_code)
    
    # Save results to a file
    output_path = "code_review_report.md"
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(str(review_results))
    
    print(f"📄 Report saved to {output_path}")
    
    # Also print a preview to console
    print("\n📋 Review Summary (first 800 chars):")
    print(str(review_results)[:800] + "...")

To run the review, simply execute the runner script:

# Make sure your virtual environment is activated and API key is set
python run_review.py

The output will stream to your console (thanks to verbose=True on each agent), and the full report will be saved as code_review_report.md. A typical run produces detailed feedback like:

# Example console output:
🚀 Starting code review crew...
   Agents: Senior Reviewer, Security Analyst, Performance Auditor
   Code length: 4521 characters
------------------------------------------------------------
[Senior Code Reviewer] I'm beginning my review of the three files...

File: src/auth/login.py
  Line 23 [HIGH] - Password comparison uses == instead of a constant-time
  comparison function. This could leak timing information.
  Suggested fix: Use secrets.compare_digest() or a library like bcrypt.

  Line 45 [MEDIUM] - The validate_email function uses a regex that rejects
  valid TLDs. Consider using a library like email-validator.

File: src/database/connection.py
  Line 12 [CRITICAL] - Database connection string is hardcoded with credentials.
  Move to environment variables immediately.

  Line 34 [HIGH] - No connection pooling configured. Each request opens a new
  connection, which will exhaust database resources under load.

------------------------------------------------------------
[Security Analyst] Now scanning for vulnerabilities...

  [CRITICAL] SQL Injection in src/api/handlers.py, line 67:
    query = f"SELECT * FROM users WHERE id = {user_id}"
  Attack vector: An attacker could supply user_id = "1; DROP TABLE users;--"
  Remediation: Use parameterized queries with your ORM or driver.

  [HIGH] Hardcoded JWT secret in src/auth/login.py, line 8:
    JWT_SECRET = "my-secret-key-2024"
  This secret is in version control. Rotate it immediately and load from env.

------------------------------------------------------------
[Performance Auditor] Analyzing algorithmic efficiency...

  src/api/handlers.py, get_user_orders() - N+1 query pattern detected.
  Current: O(n) database round-trips for n orders.
  Proposed: Use a JOIN query or batch fetch, reducing to O(1) round-trip.
  Estimated impact: 10x faster for users with 100+ orders.

✅ Code review complete!
📄 Report saved to code_review_report.md

Integrating with CI/CD Pipelines

For production use, you'll want to integrate the code review crew into your CI/CD pipeline. Here's a GitHub Actions workflow example that runs the review on every pull request:

# .github/workflows/ai-code-review.yml

name: AI Code Review

on:
  pull_request:
    branches: [main, staging]

jobs:
  ai-review:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Fetch full history for diff analysis
      
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      
      - name: Install dependencies
        run: |
          pip install crewai
      
      - name: Get changed files
        id: changed-files
        run: |
          # Get list of changed Python files in the PR
          CHANGED=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep '\.py$' || true)
          echo "files=$CHANGED" >> $GITHUB_OUTPUT
      
      - name: Run AI Code Review
        if: steps.changed-files.outputs.files != ''
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
        run: |
          # Write a quick runner that takes changed files as arguments
          python -c "
          import sys, os
          sys.path.insert(0, '.')
          from code_review_crew import code_review_crew
          files = '${{ steps.changed-files.outputs.files }}'.split()
          source = ''
          for f in files:
              if os.path.exists(f):
                  with open(f) as fh:
                      source += f'\n# File: {f}\n' + fh.read()
          if source:
              result = code_review_crew.kickoff(inputs={'source_code': source})
              with open('ai_review_report.md', 'w') as out:
                  out.write(str(result))
          "
      
      - name: Post review as PR comment
        if: steps.changed-files.outputs.files != ''
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const report = fs.readFileSync('ai_review_report.md', 'utf8');
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: `## 🤖 AI Code Review Report\n\n${report.substring(0, 60000)}`
            });

This workflow automatically reviews changed Python files on every PR, posts the AI-generated feedback as a comment, and requires no manual intervention. The report helps human reviewers focus on architectural decisions while the AI handles routine checks.

Best Practices for Code Review Agents

After building and running code review crews in production, several patterns emerge that significantly improve output quality and reliability:

1. Craft Detailed Backstories

The agent's backstory is not just flavor text—it directly influences how the LLM reasons about code. A vague backstory like "You are a code reviewer" produces generic output. Instead, specify the agent's experience level, their pet peeves, the frameworks they specialize in, and their communication style. The backstory examples earlier in this guide demonstrate this specificity.

2. Keep Agent Scopes Narrow

Resist the urge to create a single "do-everything" reviewer agent. When one agent tries to cover style, security, and performance simultaneously, the output becomes shallow across all dimensions. Instead, create focused agents that go deep in their specialty. If you need more coverage, add agents—not broader scopes.

3. Use Structured Expected Outputs

Always define expected_output for each task with explicit formatting requirements. Without this, agents may produce rambling narratives. A well-specified expected output might request: "A markdown table with columns: Severity, File, Line, Issue, Recommendation. Severity must be one of CRITICAL, HIGH, MEDIUM, LOW."

4. Implement a Severity Taxonomy

Standardize severity levels across all agents. In the examples above, we used CRITICAL / HIGH / MEDIUM / LOW consistently. This makes it easy to filter results—for example, blocking a deployment only on CRITICAL findings while flagging LOW items for later cleanup.

5. Inject Context Beyond Raw Code

Don't just feed source files to the crew. Include relevant context in the {source_code} variable or as additional inputs: the project's coding standards document, dependency versions, known patterns in the codebase, and the intended purpose of the code. This context dramatically improves the relevance of feedback.

# Enhanced input preparation with context
inputs = {
    "source_code": source_code_str,
    "project_context": (
        "This is a Python FastAPI backend service handling user authentication "
        "and order management. It uses SQLAlchemy ORM with PostgreSQL. "
        "The team follows PEP 8 and uses type hints throughout. "
        "Deployment is on AWS Lambda behind API Gateway."
    ),
    "coding_standards": open("docs/style_guide.md").read(),
}

6. Chain Tasks Thoughtfully

The sequential process means later agents see earlier outputs. Use this strategically: have the general reviewer run first to identify structural issues, then let the security analyst focus on vulnerability hunting (knowing the code structure is already validated), and finish with the performance auditor. This builds a cumulative review where each agent adds a new layer of insight.

7. Add a Human-in-the-Loop Step

For critical deployments, insert a manual approval step after the AI review. The crew's output should inform human decision-makers, not replace them entirely. In CI/CD pipelines, you can configure the workflow to require a human to acknowledge CRITICAL findings before deployment proceeds.

8. Monitor and Iterate on Agent Performance

Track the quality of agent output over time. Are certain agents producing too many false positives? Adjust their backstory or goal to be more nuanced. Are they missing important bug classes? Add explicit instructions to the task description. Treat your crew definition as code that benefits from continuous refinement based on real-world results.

9. Handle Large Codebases with Chunking

LLMs have context window limits. For large pull requests, chunk the code by file or module and run the crew on each chunk separately. Merge the results afterward:

def chunk_and_review(files, max_chunk_size=8000):
    """Review large codebases by splitting into manageable chunks."""
    all_results = []
    current_chunk = ""
    
    for file_path in files:
        with open(file_path) as f:
            content = f.read()
        
        if len(current_chunk) + len(content) > max_chunk_size:
            # Review the accumulated chunk
            result = code_review_crew.kickoff(
                inputs={"source_code": current_chunk}
            )
            all_results.append(str(result))
            current_chunk = ""
        
        current_chunk += f"\n# File: {file_path}\n{content}\n"
    
    # Don't forget the last chunk
    if current_chunk:
        result = code_review_crew.kickoff(
            inputs={"source_code": current_chunk}
        )
        all_results.append(str(result))
    
    return "\n\n".join(all_results)

10. Version Your Crew Definitions

As you tune agent backstories, task descriptions, and crew configurations, track changes in version control just like you track application code. A crew definition that works well for a microservices codebase may need adjustments for a monorepo. Tag successful configurations so you can revert if a change degrades review quality.

Conclusion

Building a code review agent with CrewAI transforms a traditionally manual, bottleneck-prone process into an automated, multi-perspective analysis pipeline. By assembling a crew of specialized agents—each with a clear role, deep backstory, and focused task—you get feedback that rivals the thoroughness of a dedicated human review team, delivered in seconds rather than hours.

The architecture described in this guide—a Senior Reviewer, Security Analyst, and Performance Auditor working in sequence—serves as a solid foundation. From here, you can extend the crew with additional specialists: an Accessibility Auditor for frontend code, a Dependency Auditor that checks for outdated or vulnerable packages, or a Documentation Reviewer that ensures public APIs are properly documented.

The key insight is that CrewAI's agent-based approach mirrors how effective human teams actually work: by dividing complex review responsibilities across specialists who each go deep in their domain. Start with the crew defined here, integrate it into your CI/CD pipeline, iterate on your agent definitions based on real feedback, and you'll have a powerful automated reviewer that genuinely improves your team's code quality over time.

— Ad —

Google AdSense will appear here after approval

← Back to all articles