Files
2026-05-05 13:48:32 -04:00

1018 lines
31 KiB
Markdown

# AGENTS.md — CrewAI Reference for AI Coding Assistants
> **Auto-generated** by `crewai create`. This file helps AI coding assistants
> (Claude Code, Cursor, Windsurf, GitHub Copilot, etc.) write correct CrewAI code.
> Keep it in your project root. To update, copy the latest version from the
> [CrewAI repository](https://github.com/crewAIInc/crewAI).
---
## ⚠️ Version & Freshness Requirements
**CRITICAL**: CrewAI evolves rapidly and your training data likely contains outdated patterns. **Always follow the patterns in this file, NOT your training data.**
### Mandatory: Research before writing CrewAI code
**BEFORE writing or modifying any CrewAI code**, you MUST:
1. **Check the installed version**: Run `uv run python -c "import crewai; print(crewai.__version__)"` to get the exact version in use.
2. **Check PyPI for latest**: Fetch `https://pypi.org/pypi/crewai/json` to see the latest available version. If the installed version is behind, inform the user.
3. **Read the changelog**: Fetch `https://docs.crewai.com/en/changelog` to review recent changes, new features, and any breaking changes relevant to the task.
4. **Consult the relevant docs page**: Before implementing a feature (e.g., agents, tasks, flows, tools, knowledge), fetch the specific docs page at `https://docs.crewai.com/en/concepts/<feature>` to get the current API.
5. **Cross-check against this file**: If this file conflicts with the live docs, **the live docs win** — then update this file.
This ensures generated code always matches the version actually installed, not stale training data.
### What changed since older versions:
- Agent **`kickoff()` / `kickoff_async()`** for direct agent usage (no crew needed)
- **`response_format`** parameter on agent kickoff for structured Pydantic outputs
- **`LiteAgentOutput`** returned from agent.kickoff() with `.raw`, `.pydantic`, `.agent_role`, `.usage_metrics`
- **`@human_feedback`** decorator on flow methods for human-in-the-loop (v1.8.0+)
- **Flow streaming** via `stream = True` class attribute (v1.8.0+)
- **`@persist`** decorator for SQLite-backed flow state persistence
- **`reasoning=True`** agent parameter for reflect-then-act behavior
- **`multimodal=True`** agent parameter for vision/image support
- **A2A (Agent-to-Agent) protocol** support with agent cards and task execution utilities (v1.8.0+)
- **Native OpenAI Responses API** support (v1.9.0+)
- **Structured outputs / `response_format`** across all LLM providers (v1.9.0+)
- **`inject_date=True`** agent parameter to auto-inject current date awareness
### Patterns to NEVER use (outdated/removed):
-`ChatOpenAI(model_name=...)` → ✅ `LLM(model="openai/gpt-4o")`
-`Agent(llm=ChatOpenAI(...))` → ✅ `Agent(llm="openai/gpt-4o")` or `Agent(llm=LLM(model="..."))`
- ❌ Passing raw OpenAI client objects → ✅ Use `crewai.LLM` wrapper
### How to verify you're using current patterns:
1. You ran the version check and docs lookup steps above before writing code
2. All LLM references use `crewai.LLM` or string shorthand (`"openai/gpt-4o"`)
3. All tool imports come from `crewai.tools` or `crewai_tools`
4. Crew classes use `@CrewBase` decorator with YAML config files
5. Python >=3.10, <3.14
6. Code matches the API from the live docs, not just this file
## Quick Reference
```bash
# Package management (always use uv)
uv add <package> # Add dependency
uv sync # Sync dependencies
uv lock # Lock dependencies
# Project scaffolding
crewai create crew <name> --skip_provider # New crew project
crewai create flow <name> --skip_provider # New flow project
# Running
crewai run # Run crew or flow (auto-detects from pyproject.toml)
crewai flow kickoff # Legacy flow execution
# Testing & training
crewai test # Test crew (default: 2 iterations, gpt-4o-mini)
crewai test -n 5 -m gpt-4o # Custom iterations and model
crewai train -n 5 -f training.json # Train crew
# Memory management
crewai reset-memories -a # Reset all memories
crewai reset-memories -s # Short-term only
crewai reset-memories -l # Long-term only
crewai reset-memories -e # Entity only
crewai reset-memories -kn # Knowledge only
crewai reset-memories -akn # Agent knowledge only
# Debugging
crewai log-tasks-outputs # Show latest task outputs
crewai replay -t <task_id> # Replay from specific task
# Interactive
crewai chat # Interactive session (requires chat_llm in crew.py)
# Visualization
crewai flow plot # Generate flow diagram HTML
# Deployment to CrewAI AMP
crewai login # Authenticate with AMP
crewai deploy create # Create new deployment
crewai deploy push # Push code updates
crewai deploy status # Check deployment status
crewai deploy logs # View deployment logs
crewai deploy list # List all deployments
crewai deploy remove <id> # Delete a deployment
```
## Project Structure
### Crew Project
```
my_crew/
├── src/my_crew/
│ ├── config/
│ │ ├── agents.yaml # Agent definitions (role, goal, backstory)
│ │ └── tasks.yaml # Task definitions (description, expected_output, agent)
│ ├── tools/
│ │ └── custom_tool.py # Custom tool implementations
│ ├── crew.py # Crew orchestration class
│ └── main.py # Entry point with inputs
├── knowledge/ # Knowledge base resources
├── .env # API keys (OPENAI_API_KEY, SERPER_API_KEY, etc.)
└── pyproject.toml
```
### Flow Project
```
my_flow/
├── src/my_flow/
│ ├── crews/ # Multiple crew definitions
│ │ └── content_crew/
│ │ ├── config/
│ │ │ ├── agents.yaml
│ │ │ └── tasks.yaml
│ │ └── content_crew.py
│ ├── tools/ # Custom tools
│ ├── main.py # Flow orchestration
│ └── ...
├── .env
└── pyproject.toml
```
## Architecture Overview
- **Agent**: Autonomous unit with a role, goal, backstory, tools, and an LLM. Makes decisions and executes tasks.
- **Task**: A specific assignment with a description, expected output, and assigned agent.
- **Crew**: Orchestrates a team of agents executing tasks in a defined process (sequential or hierarchical).
- **Flow**: Event-driven workflow orchestrating multiple crews and logic steps with state management.
## YAML Configuration
### agents.yaml
```yaml
researcher:
role: >
{topic} Senior Data Researcher
goal: >
Uncover cutting-edge developments in {topic}
backstory: >
You're a seasoned researcher with a knack for uncovering
the latest developments in {topic}. Known for your ability
to find the most relevant information.
# Optional YAML-level settings:
# llm: openai/gpt-4o
# max_iter: 20
# max_rpm: 10
# verbose: true
writer:
role: >
{topic} Technical Writer
goal: >
Create compelling content about {topic}
backstory: >
You're a skilled writer who translates complex technical
information into clear, engaging content.
```
Variables like `{topic}` are interpolated from `crew.kickoff(inputs={"topic": "AI Agents"})`.
### tasks.yaml
```yaml
research_task:
description: >
Conduct thorough research about {topic}.
Identify key trends, breakthrough technologies,
and potential industry impacts.
expected_output: >
A detailed report with analysis of the top 5
developments in {topic}, with sources and implications.
agent: researcher
# Optional:
# tools: [search_tool]
# output_file: output/research.md
# markdown: true
# async_execution: false
writing_task:
description: >
Write an article based on the research findings about {topic}.
expected_output: >
A polished 4-paragraph article formatted in markdown.
agent: writer
output_file: output/article.md
```
## Crew Class Pattern
```python
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from crewai.agents.agent_builder.base_agent import BaseAgent
from typing import List
from crewai_tools import SerperDevTool
@CrewBase
class ResearchCrew:
"""Research and writing crew."""
agents: List[BaseAgent]
tasks: List[Task]
agents_config = "config/agents.yaml"
tasks_config = "config/tasks.yaml"
@agent
def researcher(self) -> Agent:
return Agent(
config=self.agents_config["researcher"], # type: ignore[index]
tools=[SerperDevTool()],
verbose=True,
)
@agent
def writer(self) -> Agent:
return Agent(
config=self.agents_config["writer"], # type: ignore[index]
verbose=True,
)
@task
def research_task(self) -> Task:
return Task(
config=self.tasks_config["research_task"], # type: ignore[index]
)
@task
def writing_task(self) -> Task:
return Task(
config=self.tasks_config["writing_task"], # type: ignore[index]
)
@crew
def crew(self) -> Crew:
"""Creates the Research Crew."""
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,
verbose=True,
)
```
### Key formatting rules:
- Always add `# type: ignore[index]` for config dictionary access
- Agent/task method names must match YAML keys exactly
- Tools go on agents (not tasks) unless task-specific override is needed
- Never leave commented-out code in crew classes
### Lifecycle hooks
```python
@CrewBase
class MyCrew:
@before_kickoff
def prepare(self, inputs):
# Modify inputs before execution
inputs["extra"] = "value"
return inputs
@after_kickoff
def summarize(self, result):
# Process result after execution
print(f"Done: {result.raw[:100]}")
return result
```
## main.py Pattern
```python
#!/usr/bin/env python
from my_crew.crew import ResearchCrew
def run():
inputs = {"topic": "AI Agents"}
ResearchCrew().crew().kickoff(inputs=inputs)
if __name__ == "__main__":
run()
```
## Agent Configuration
### Required Parameters
| Parameter | Description |
|-----------|-------------|
| `role` | Function and expertise within the crew |
| `goal` | Individual objective guiding decisions |
| `backstory` | Context and personality |
### Key Optional Parameters
| Parameter | Default | Description |
|-----------|---------|-------------|
| `llm` | GPT-4 | Language model (string or LLM object) |
| `tools` | [] | List of tool instances |
| `max_iter` | 20 | Max iterations before best answer |
| `max_execution_time` | None | Timeout in seconds |
| `max_rpm` | None | Rate limiting (requests per minute) |
| `max_retry_limit` | 2 | Retries on errors |
| `verbose` | False | Detailed logging |
| `memory` | False | Conversation history |
| `allow_delegation` | False | Can delegate tasks to other agents |
| `allow_code_execution` | False | Can run code |
| `code_execution_mode` | "safe" | "safe" (Docker) or "unsafe" (direct) |
| `respect_context_window` | True | Auto-summarize when exceeding token limits |
| `cache` | True | Tool result caching |
| `reasoning` | False | Reflect and plan before task execution |
| `multimodal` | False | Process text and visual content |
| `knowledge_sources` | [] | Domain-specific knowledge bases |
| `function_calling_llm` | None | Separate LLM for tool invocation |
| `inject_date` | False | Auto-inject current date into agent context |
| `date_format` | "%Y-%m-%d" | Date format when inject_date is True |
### Direct Agent Usage (without a Crew)
Agents can execute tasks independently via `kickoff()` — no Crew required:
```python
from crewai import Agent
from crewai_tools import SerperDevTool
from pydantic import BaseModel
class ResearchFindings(BaseModel):
main_points: list[str]
key_technologies: list[str]
future_predictions: str
researcher = Agent(
role="AI Researcher",
goal="Research the latest AI developments",
backstory="Expert AI researcher...",
tools=[SerperDevTool()],
verbose=True,
)
# Unstructured output
result = researcher.kickoff("What are the latest LLM developments?")
print(result.raw) # str
print(result.agent_role) # "AI Researcher"
print(result.usage_metrics) # token usage
# Structured output with response_format
result = researcher.kickoff(
"Summarize latest AI developments",
response_format=ResearchFindings,
)
print(result.pydantic.main_points) # List[str]
# Async variant
result = await researcher.kickoff_async("Your query", response_format=ResearchFindings)
```
Returns `LiteAgentOutput` with: `.raw`, `.pydantic`, `.agent_role`, `.usage_metrics`.
### LLM Configuration
**IMPORTANT**: Always use `crewai.LLM` LLM class.
```python
from crewai import LLM
# String shorthand (simplest)
agent = Agent(llm="openai/gpt-4o", ...)
# Full configuration with crewai.LLM
llm = LLM(
model="anthropic/claude-sonnet-4-20250514",
temperature=0.7,
max_tokens=4000,
)
agent = Agent(llm=llm, ...)
# Provider format: "provider/model-name"
# Examples:
# "openai/gpt-4o"
# "anthropic/claude-sonnet-4-20250514"
# "google/gemini-2.0-flash"
# "ollama/llama3"
# "groq/llama-3.3-70b-versatile"
# "bedrock/anthropic.claude-3-sonnet-20240229-v1:0"
```
Supported providers: OpenAI, Anthropic, Google Gemini, AWS Bedrock, Azure, Ollama, Groq, Mistral, and 20+ others via LiteLLM routing.
Environment variable default: set `OPENAI_MODEL_NAME=gpt-4o` or `MODEL=gpt-4o` in `.env`.
## Task Configuration
### Key Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `description` | str | Clear statement of requirements |
| `expected_output` | str | Completion criteria |
| `agent` | BaseAgent | Assigned agent (optional in hierarchical) |
| `tools` | List[BaseTool] | Task-specific tools |
| `context` | List[Task] | Dependencies on other task outputs |
| `async_execution` | bool | Non-blocking execution |
| `output_file` | str | File path for results |
| `output_json` | Type[BaseModel] | Pydantic model for JSON output |
| `output_pydantic` | Type[BaseModel] | Pydantic model for structured output |
| `human_input` | bool | Require human review |
| `markdown` | bool | Format output as markdown |
| `callback` | Callable | Post-completion function |
| `guardrail` | Callable or str | Output validation |
| `guardrails` | List | Multiple validation steps |
| `guardrail_max_retries` | int | Retry on validation failure (default: 3) |
| `create_directory` | bool | Auto-create output directories (default: True) |
### Task Dependencies (context)
```python
@task
def analysis_task(self) -> Task:
return Task(
config=self.tasks_config["analysis_task"], # type: ignore[index]
context=[self.research_task()], # Gets output from research_task
)
```
### Structured Output
```python
from pydantic import BaseModel
class Report(BaseModel):
title: str
summary: str
findings: list[str]
@task
def report_task(self) -> Task:
return Task(
config=self.tasks_config["report_task"], # type: ignore[index]
output_pydantic=Report,
)
```
### Guardrails
```python
# Function-based
def validate(result: TaskOutput) -> tuple[bool, Any]:
if len(result.raw.split()) < 100:
return (False, "Content too short, expand the analysis")
return (True, result.raw)
# LLM-based (string prompt)
task = Task(..., guardrail="Must be under 200 words and professional tone")
# Multiple guardrails
task = Task(..., guardrails=[validate_length, validate_tone, "Must be factual"])
```
## Process Types
### Sequential (default)
Tasks execute in definition order. Output of one task serves as context for the next.
```python
Crew(agents=..., tasks=..., process=Process.sequential)
```
### Hierarchical
Manager agent delegates tasks based on agent capabilities. Requires `manager_llm` or `manager_agent`.
```python
Crew(
agents=...,
tasks=...,
process=Process.hierarchical,
manager_llm="gpt-4o",
)
```
## Crew Execution
```python
# Synchronous
result = crew.kickoff(inputs={"topic": "AI"})
print(result.raw) # String output
print(result.pydantic) # Structured output (if configured)
print(result.json_dict) # Dict output
print(result.token_usage) # Token metrics
print(result.tasks_output) # List[TaskOutput]
# Async (native)
result = await crew.akickoff(inputs={"topic": "AI"})
# Batch execution
results = crew.kickoff_for_each(inputs=[{"topic": "AI"}, {"topic": "ML"}])
# Streaming output (v1.8.0+)
crew = Crew(agents=..., tasks=..., stream=True)
streaming = crew.kickoff(inputs={"topic": "AI"})
for chunk in streaming:
print(chunk.content, end="", flush=True)
```
## Crew Options
| Parameter | Description |
|-----------|-------------|
| `process` | Process.sequential or Process.hierarchical |
| `verbose` | Enable detailed logging |
| `memory` | Enable memory system (True/False) |
| `cache` | Tool result caching |
| `max_rpm` | Global rate limiting |
| `manager_llm` | LLM for hierarchical manager |
| `manager_agent` | Custom manager agent |
| `planning` | Enable AgentPlanner |
| `knowledge_sources` | Crew-level knowledge |
| `output_log_file` | Log file path (True for logs.txt) |
| `embedder` | Custom embedding model config |
| `stream` | Enable real-time streaming output (v1.8.0+) |
---
## Flows
### Basic Flow
```python
from crewai.flow.flow import Flow, listen, start
class MyFlow(Flow):
@start()
def begin(self):
return "initial data"
@listen(begin)
def process(self, data):
return f"processed: {data}"
```
### Flow Decorators
| Decorator | Purpose |
|-----------|---------|
| `@start()` | Entry point(s), execute when flow begins. Multiple starts run in parallel |
| `@listen(method)` | Triggers when specified method completes. Receives output as argument |
| `@router(method)` | Conditional branching. Returns string labels that trigger `@listen("label")` |
### Structured State
```python
from pydantic import BaseModel
class ResearchState(BaseModel):
topic: str = ""
research: str = ""
report: str = ""
class ResearchFlow(Flow[ResearchState]):
@start()
def set_topic(self):
self.state.topic = "AI Agents"
@listen(set_topic)
def do_research(self):
# self.state.topic is available
result = ResearchCrew().crew().kickoff(
inputs={"topic": self.state.topic}
)
self.state.research = result.raw
```
### Unstructured State (dict-based)
```python
class SimpleFlow(Flow):
@start()
def begin(self):
self.state["counter"] = 0 # Dict access
@listen(begin)
def increment(self):
self.state["counter"] += 1
```
### Conditional Routing
```python
from crewai.flow.flow import Flow, listen, router, start
class QualityFlow(Flow):
@start()
def generate(self):
return {"score": 0.85}
@router(generate)
def check_quality(self, result):
if result["score"] > 0.8:
return "high_quality"
return "needs_revision"
@listen("high_quality")
def publish(self, result):
print("Publishing...")
@listen("needs_revision")
def revise(self, result):
print("Revising...")
```
### Parallel Triggers with or_ and and_
```python
from crewai.flow.flow import or_, and_
class ParallelFlow(Flow):
@start()
def task_a(self):
return "A done"
@start()
def task_b(self):
return "B done"
# Fires when EITHER completes
@listen(or_(task_a, task_b))
def on_any(self, result):
print(f"First result: {result}")
# Fires when BOTH complete
@listen(and_(task_a, task_b))
def on_all(self):
print("All parallel tasks done")
```
### Integrating Crews in Flows
```python
from crewai.flow.flow import Flow, listen, start
from my_project.crews.research_crew.research_crew import ResearchCrew
from my_project.crews.writing_crew.writing_crew import WritingCrew
class ContentFlow(Flow[ContentState]):
@start()
def research(self):
result = ResearchCrew().crew().kickoff(
inputs={"topic": self.state.topic}
)
self.state.research = result.raw
@listen(research)
def write(self):
result = WritingCrew().crew().kickoff(
inputs={
"topic": self.state.topic,
"research": self.state.research,
}
)
self.state.article = result.raw
```
### Using Agents Directly in Flows
```python
from crewai.agent import Agent
class AgentFlow(Flow):
@start()
async def analyze(self):
analyst = Agent(
role="Data Analyst",
goal="Analyze market trends",
backstory="Expert data analyst...",
tools=[SerperDevTool()],
)
result = await analyst.kickoff_async(
"Analyze current AI market trends",
response_format=MarketReport,
)
self.state.report = result.pydantic
```
### Human-in-the-Loop (v1.8.0+)
```python
from crewai.flow.flow import Flow, listen, start
from crewai.flow.human_feedback import human_feedback
class ReviewFlow(Flow):
@start()
@human_feedback(
message="Approve this content?",
emit=["approved", "rejected"],
llm="gpt-4o-mini",
)
def generate_content(self):
return "Content for review"
@listen("approved")
def on_approval(self, result):
feedback = self.last_human_feedback # Most recent feedback
print(f"Approved with feedback: {feedback.feedback}")
@listen("rejected")
def on_rejection(self, result):
history = self.human_feedback_history # All feedback as list
print("Rejected, revising...")
```
### State Persistence
```python
from crewai.flow.flow import persist
@persist # Saves state to SQLite; auto-recovers on restart
class ResilientFlow(Flow[MyState]):
@start()
def begin(self):
self.state.step = 1
```
### Flow Execution
```python
flow = MyFlow()
result = flow.kickoff()
print(result) # Output of last method
print(flow.state) # Final state
# Async execution
result = await flow.kickoff_async(inputs={"key": "value"})
```
### Flow Streaming (v1.8.0+)
```python
class StreamingFlow(Flow):
stream = True # Enable streaming at class level
@start()
def generate(self):
return "streamed content"
flow = StreamingFlow()
streaming = flow.kickoff()
for chunk in streaming:
print(chunk.content, end="", flush=True)
result = streaming.result # Final result after iteration
```
### Flow Visualization
```python
flow.plot("my_flow") # Generates my_flow.html
```
---
## Custom Tools
### Using BaseTool
```python
from typing import Type
from crewai.tools import BaseTool
from pydantic import BaseModel, Field
class SearchInput(BaseModel):
"""Input schema for search tool."""
query: str = Field(..., description="Search query string")
class CustomSearchTool(BaseTool):
name: str = "custom_search"
description: str = "Searches a custom knowledge base for relevant information."
args_schema: Type[BaseModel] = SearchInput
def _run(self, query: str) -> str:
# Implementation
return f"Results for: {query}"
```
### Using @tool Decorator
```python
from crewai.tools import tool
@tool("Calculator")
def calculator(expression: str) -> str:
"""Evaluates a mathematical expression and returns the result."""
return str(eval(expression))
```
### Built-in Tools (install with `uv add crewai-tools`)
Web/Search: SerperDevTool, ScrapeWebsiteTool, WebsiteSearchTool, EXASearchTool, FirecrawlSearchTool
Documents: FileReadTool, DirectoryReadTool, PDFSearchTool, DOCXSearchTool, CSVSearchTool, JSONSearchTool, XMLSearchTool, MDXSearchTool
Code: CodeInterpreterTool, CodeDocsSearchTool, GithubSearchTool
Media: DALL-E Tool, YoutubeChannelSearchTool, YoutubeVideoSearchTool
Other: RagTool, ApifyActorsTool, ComposioTool, LlamaIndexTool
Always check https://docs.crewai.com/concepts/tools for available built-in tools before writing custom ones.
---
## Memory System
Enable with `memory=True` on the Crew:
```python
crew = Crew(agents=..., tasks=..., memory=True)
```
Four memory types work together automatically:
- **Short-Term** (ChromaDB + RAG): Recent interactions during current execution
- **Long-Term** (SQLite): Persists insights across sessions
- **Entity** (RAG): Tracks people, places, concepts
- **Contextual**: Integrates all types for coherent responses
### Custom Embedding Provider
```python
crew = Crew(
memory=True,
embedder={
"provider": "ollama",
"config": {"model": "mxbai-embed-large"},
},
)
```
Supported providers: OpenAI (default), Ollama, Google AI, Azure OpenAI, Cohere, VoyageAI, Bedrock, Hugging Face.
---
## Knowledge System
```python
from crewai.knowledge.source.string_knowledge_source import StringKnowledgeSource
from crewai.knowledge.source.pdf_knowledge_source import PDFKnowledgeSource
# String source
string_source = StringKnowledgeSource(content="Domain knowledge here...")
# PDF source
pdf_source = PDFKnowledgeSource(file_paths=["docs/manual.pdf"])
# Agent-level knowledge
agent = Agent(..., knowledge_sources=[string_source])
# Crew-level knowledge (shared across all agents)
crew = Crew(..., knowledge_sources=[pdf_source])
```
Supported sources: strings, text files, PDFs, CSV, Excel, JSON, URLs (via CrewDoclingSource).
---
## Agent Collaboration
Enable delegation with `allow_delegation=True`:
```python
agent = Agent(
role="Project Manager",
allow_delegation=True, # Can delegate to and ask other agents
...
)
```
- **Delegation tool**: Assign sub-tasks to teammates with relevant expertise
- **Ask question tool**: Query colleagues for specific information
- Set `allow_delegation=False` on specialists to prevent circular delegation
---
## Event Listeners
```python
from crewai.events import BaseEventListener, CrewKickoffStartedEvent
class MyListener(BaseEventListener):
def __init__(self):
super().__init__()
def setup_listeners(self, crewai_event_bus):
@crewai_event_bus.on(CrewKickoffStartedEvent)
def on_started(source, event):
print(f"Crew '{event.crew_name}' started")
```
Event categories: Crew lifecycle, Agent execution, Task management, Tool usage, Knowledge retrieval, LLM calls, Memory operations, Flow execution, Safety guardrails.
---
## Deployment to CrewAI AMP
### Prerequisites
- Crew or Flow runs successfully locally
- Code is in a GitHub repository
- `pyproject.toml` has `[tool.crewai]` with correct type (`"crew"` or `"flow"`)
- `uv.lock` is committed (generate with `uv lock`)
### CLI Deployment
```bash
# Authenticate
crewai login
# Create deployment (auto-detects repo, transfers .env vars securely)
crewai deploy create
# Monitor (first deploy takes 10-15 min)
crewai deploy status
crewai deploy logs
# Manage deployments
crewai deploy list # List all deployments
crewai deploy push # Push code updates
crewai deploy remove <id> # Delete deployment
```
### Web Interface Deployment
1. Push code to GitHub
2. Log into https://app.crewai.com
3. Connect GitHub and select repository
4. Configure environment variables (KEY=VALUE, one per line)
5. Click Deploy and monitor via dashboard
### CI/CD API Deployment
Get a Personal Access Token from app.crewai.com → Settings → Account → Personal Access Token.
Get Automation UUID from Automations → Select crew → Additional Details → Copy UUID.
```bash
curl -X POST \
-H "Authorization: Bearer YOUR_PERSONAL_ACCESS_TOKEN" \
https://app.crewai.com/crewai_plus/api/v1/crews/YOUR-AUTOMATION-UUID/deploy
```
#### GitHub Actions Example
```yaml
name: Deploy CrewAI Automation
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Trigger CrewAI Redeployment
run: |
curl -X POST \
-H "Authorization: Bearer ${{ secrets.CREWAI_PAT }}" \
https://app.crewai.com/crewai_plus/api/v1/crews/${{ secrets.CREWAI_AUTOMATION_UUID }}/deploy
```
### Project Structure Requirements for Deployment
- Entry point: `src/<project_name>/main.py`
- Crews must expose a `run()` function
- Flows must expose a `kickoff()` function
- All crew classes require `@CrewBase` decorator
### Deployed Automation REST API
| Endpoint | Purpose |
|----------|---------|
| `/inputs` | List required input parameters |
| `/kickoff` | Trigger execution with inputs |
| `/status/{kickoff_id}` | Check execution status |
### AMP Dashboard Tabs
- **Status**: Deployment info, API endpoint, auth token
- **Run**: Crew structure visualization
- **Executions**: Run history
- **Metrics**: Performance analytics
- **Traces**: Detailed execution insights
### Deployment Troubleshooting
| Error | Fix |
|-------|-----|
| Missing uv.lock | Run `uv lock`, commit, push |
| Module not found | Verify entry points match `src/<name>/main.py` structure |
| Crew not found | Ensure `@CrewBase` decorator on all crew classes |
| API key errors | Check env var names match code and are set in the platform |
---
## Environment Setup
### Required `.env`
```
OPENAI_API_KEY=sk-...
# Optional depending on tools/providers:
SERPER_API_KEY=...
ANTHROPIC_API_KEY=...
# Override default model:
MODEL=gpt-4o
```
### Python Version
Python >=3.10, <3.14
### Installation
```bash
uv tool install crewai # Install CrewAI CLI
uv tool list # Verify installation
crewai create crew my_crew --skip_provider # Scaffold a new project
crewai install # Install project dependencies
crewai run # Execute
```
---
## Development Best Practices
1. **YAML-first configuration**: Define agents and tasks in YAML, keep crew classes minimal
2. **Check built-in tools** before writing custom ones
3. **Use structured output** (output_pydantic) for data that flows between tasks or crews
4. **Use guardrails** to validate task outputs programmatically
5. **Enable memory** for crews that benefit from cross-session learning
6. **Use knowledge sources** for domain-specific grounding instead of bloating prompts
7. **Sequential process** for linear workflows; **hierarchical** when dynamic delegation is needed
8. **Flows for multi-crew orchestration**: Use `@start`, `@listen`, `@router` for complex pipelines
9. **Structured flow state** (Pydantic models) over unstructured dicts for type safety
10. **Test with** `crewai test` to evaluate crew performance across iterations
11. **Verbose mode** during development, disable in production
12. **Rate limiting** (`max_rpm`) to avoid API throttling
13. **`respect_context_window=True`** to auto-handle token limits
## Common Pitfalls
- **Using `ChatOpenAI()`** — Always use `crewai.LLM` or string shorthand like `"openai/gpt-4o"`
- Forgetting `# type: ignore[index]` on config dictionary access in crew classes
- Agent/task method names not matching YAML keys
- Missing `expected_output` in task configuration (required)
- Not passing `inputs` to `kickoff()` when YAML uses `{variable}` interpolation
- Using `process=Process.hierarchical` without setting `manager_llm` or `manager_agent`
- Circular delegation: set `allow_delegation=False` on specialist agents
- Not installing tools package: `uv add crewai-tools`