# PR review agent (/cookbooks/pr-review-agent)

Build a PR review agent that runs on every pull request, reads your repo's `CLAUDE.md` or `AGENTS.md`, reviews the diff against those rules, and posts structured feedback as a comment. About 40 lines of Python and a 20-line GitHub Action.

[View source on GitHub](https://github.com/ComposioHQ/composio/tree/next/docs/examples/pr-review-agent)

# What you'll build

* An AI reviewer that runs automatically on every PR via GitHub Actions
* Reads `CLAUDE.md` or `AGENTS.md` from your repo to enforce project-specific rules
* Posts structured reviews with categorized issues, security analysis, and test coverage checks

# Prerequisites

* Python 3.10+
* [Composio API key](https://platform.composio.dev/settings)
* [OpenAI API key](https://platform.openai.com/api-keys)
* A GitHub repository where you have admin access (for adding secrets and workflows)

**Stack:** Python, OpenAI Agents SDK, Composio, GitHub Actions

# Set up the project

Create a new directory and install dependencies:

```bash
mkdir pr-review-agent && cd pr-review-agent
pip install composio composio-openai-agents openai-agents
```

> Get your `COMPOSIO_API_KEY` from [Settings](https://platform.composio.dev/settings) and `OPENAI_API_KEY` from [OpenAI](https://platform.openai.com/api-keys).

Set your API keys:

```bash title=".env"
COMPOSIO_API_KEY=your_composio_api_key
OPENAI_API_KEY=your_openai_api_key
```
# Build the agent

Create `agent.py`:

```py title="agent.py"
import asyncio
import os

from agents import Agent, Runner
from composio_openai_agents import OpenAIAgentsProvider

from composio import Composio

composio = Composio(provider=OpenAIAgentsProvider())

session = composio.create(
    user_id="user_123",
    toolkits=["github"],
)

tools = session.tools()

agent = Agent(
    name="PR Reviewer",
    instructions="""You are PR-Reviewer, an AI code reviewer for GitHub pull requests.

**Step 1: Gather context**
- Fetch the PR details (title, description, author).
- List all changed files and read the diff.
- Check if the repo has a CLAUDE.md or AGENTS.md at the root.
  If found, read it and treat its rules as your review checklist.

**Step 2: Analyze the diff**
Focus only on new code added in the PR. For each changed file, look for:
- Bugs and logic errors
- Security issues (exposed secrets, injection, XSS)
- Performance problems (unnecessary loops, N+1 queries)
- Violations of CLAUDE.md / AGENTS.md rules (if the file exists)
- Whether tests were added or updated

Do NOT flag:
- Style preferences or minor wording changes
- Issues in unchanged code that existed before the PR
- Missing docstrings, type hints, or comments
- Things that would be caught by a linter or CI

For each file, ask: "Would this change break something or mislead someone?"
If no, move on.

**Step 3: Post your review as a PR comment**
Use this format:

# PR Review

**Summary**: [2-3 sentences on what this PR does]

**Review effort [1-5]**: [1 = trivial, 5 = complex and risky]

## Key issues
| # | File | Lines | Category | Description |
|---|------|-------|----------|-------------|
| 1 | `file.py` | 12-15 | Possible bug | [description] |

Categories: `possible bug`, `security`, `performance`, `best practice`

If no issues found, write "No issues found" instead of the table.

## Security concerns
[Any security issues, or "None"]

## CLAUDE.md / AGENTS.md compliance
[Rule violations, or "No project rules file found" / "All rules followed"]

## Tests
[Were relevant tests added? Yes/No with brief explanation]

Be specific and actionable. Don't invent issues to seem thorough.
If the PR looks good, say so.""",
    tools=tools,
)

async def main():
    repo = os.environ.get("GITHUB_REPO", "composiohq/composio")
    pr_number = os.environ.get("PR_NUMBER", "2800")

    result = await Runner.run(
        starting_agent=agent,
        input=f"Review pull request #{pr_number} in the {repo} repository.",
    )
    print(result.final_output)

asyncio.run(main())

```
Here's what's happening:

1. **Session creation**: `composio.create(user_id="user_123", toolkits=["github"])` creates a session with GitHub tools like `GITHUB_GET_A_PULL_REQUEST`, `GITHUB_LIST_PULL_REQUESTS_FILES`, and `GITHUB_CREATE_A_REVIEW_FOR_A_PULL_REQUEST`.

2. **CLAUDE.md / AGENTS.md as review rules**: The agent checks for either file in the repo root and uses it as its review checklist. Your existing project standards become the review guide with zero extra setup.

3. **Focused review**: The agent only flags new code that could break something or mislead someone. It skips style preferences, pre-existing issues, and anything CI already catches.

# Run it locally

```bash
python agent.py
```
If you haven't connected GitHub yet, the agent will prompt you with an auth link. Authorize and rerun.

To review a specific PR:

```bash
GITHUB_REPO=owner/repo PR_NUMBER=42 python agent.py
```
# Run it on every PR with GitHub Actions

Add `agent.py` to the root of your repo, then create `.github/workflows/review.yml`:

```yml title=".github/workflows/review.yml"
name: PR Review Agent

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Install dependencies
        run: pip install composio composio-openai-agents openai-agents

      - name: Run PR review
        env:
          COMPOSIO_API_KEY: ${{ secrets.COMPOSIO_API_KEY }}
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          GITHUB_REPO: ${{ github.repository }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
        run: python agent.py

```
Your repo should look like this:

```
your-repo/
├── agent.py
├── .github/workflows/review.yml
└── CLAUDE.md (optional)
```
Then set up your repo:

1. Go to **Settings > Secrets and variables > Actions**
2. Add `COMPOSIO_API_KEY` and `OPENAI_API_KEY` as repository secrets
3. **Connect GitHub to Composio** (one-time setup). The agent runs as `user_123` in CI, so that user needs a GitHub connection before the workflow can post reviews:

```bash
python -c "
from composio import Composio
composio = Composio()
session = composio.create(user_id='user_123', toolkits=['github'])
connection = session.authorize('github')
print('Visit this URL to connect GitHub:', connection.redirect_url)
connection.wait_for_connection()
print('Connected!')
"
```

After you authorize once, the connection persists. The GitHub Action will work for all future PRs.

# How it works

When a PR is opened:

1. GitHub Actions triggers the workflow and runs `agent.py`
2. The agent creates a Composio session with GitHub tools
3. It fetches the PR details and diffs using `GITHUB_GET_A_PULL_REQUEST` and `GITHUB_LIST_PULL_REQUESTS_FILES`
4. It checks for `CLAUDE.md` or `AGENTS.md` in the repo root
5. It reviews the diff and posts a structured comment using `GITHUB_CREATE_A_REVIEW_FOR_A_PULL_REQUEST`

Composio handles OAuth, tool discovery, and API execution. You don't write any GitHub API code.

# Take it further

- [Build a Chat App](/cookbooks/chat-app): 
Build a full chat interface with tool calling

- [Configuring sessions](/docs/configuring-sessions): 
Lock down which toolkits and tools your agent can access

- [Authenticating users](/docs/authenticating-users/manually-authenticating): 
Authenticate users ahead of time during onboarding

---

📚 **More documentation:** [View all docs](https://docs.composio.dev/llms.txt) | [Glossary](https://docs.composio.dev/llms.mdx/docs/glossary) | [Cookbooks](https://docs.composio.dev/llms.mdx/cookbooks) | [API Reference](https://docs.composio.dev/llms.mdx/reference)

---

# Composio SDK — Instructions for AI Code Generators

**Purpose:** Enforce only the **current** and **correct** patterns for integrating [Composio](https://composio.dev/) tools into AI agents.
**Scope:** All AI-generated code using Composio must follow these guardrails.

---

## 1. Correct Composio Integration

Composio supports two integration modes: **Native Tools** (with a provider package) and **MCP** (no provider package needed).

### Native Tools

```python
# ✅ CORRECT — Python (defaults to OpenAI)
from composio import Composio

composio = Composio()
session = composio.create(user_id="user_123")
tools = session.tools()
# Pass tools to your agent/LLM framework
```

```typescript
// ✅ CORRECT — TypeScript (defaults to OpenAI)
import { Composio } from "@composio/core";

const composio = new Composio();
const session = await composio.create("user_123");
const tools = await session.tools();
// Pass tools to your agent/LLM framework
```

For other providers, pass the provider explicitly. Provider packages follow the naming convention: `composio_<provider>` for Python, `@composio/<provider>` for TypeScript.

### MCP

Use `session.mcp.url` and `session.mcp.headers` with any MCP-compatible client (Claude Desktop, Cursor, OpenAI Agents, etc.). No provider package needed.

---

## 2. CRITICAL INSTRUCTIONS FOR AI MODELS

### 2.1 — ALWAYS DO THE FOLLOWING

1. **Use `composio.create(user_id)`** to create a session — this is the entry point for all Composio integrations.
2. **Use `session.tools()`** for native tool integration or **`session.mcp.url`** for MCP integration.
3. **Import** from the correct provider package (`composio_<provider>` for Python, `@composio/<provider>` for TypeScript).
4. **Pass `user_id` to `composio.create()`**, not to individual tool calls.

### 2.2 — NEVER DO THE FOLLOWING

1. **Do not** instruct users to manually create auth configs or connected accounts before running.
2. **Do not** import from `composio_openai` / `@composio/openai` when using OpenAI Agents SDK — use `composio_openai_agents` / `@composio/openai-agents` instead.

### 2.3 — DISCOURAGED (do not use unless user explicitly asks)

Do **not** generate `composio.tools.get()`, `composio.tools.execute()`, or `composio.provider.handle_tool_calls()` unless the user explicitly requests direct tool execution. These are a supported but **not recommended** low-level interface.


---

## Terminology Migration (old → current)

If you encounter these terms in error messages, old documentation, or user prompts, translate them to the current equivalents. **Do not use the old terms in generated code or explanations.**

| Old term (v1/v2) | Current term (v3) | In code |
|---|---|---|
| entity ID | user ID | `user_id` parameter |
| actions | tools | e.g., `GITHUB_CREATE_ISSUE` is a *tool* |
| apps / appType | toolkits | e.g., `github` is a *toolkit* |
| integration / integration ID | auth config / auth config ID | `auth_config_id` parameter |
| connection | connected account | `connected_accounts` namespace |
| ComposioToolSet / OpenAIToolSet | `Composio` class with a provider | `Composio(provider=...)` |
| toolset | provider | e.g., `OpenAIProvider` |

If a user says "entity ID", they mean `user_id`. If they say "integration", they mean "auth config". Always respond using the current terminology.

