Build a Multi-Agent Job Research Crew
Build and deploy a 3-agent AI crew that researches companies for job applications.
Introduction
30 Second Summary
Preparing for a job interview means hours of researching a company, figuring out what skills matter most, and pulling it all together into notes you can actually use. What if you had a team of AI specialists who could do that research for you in seconds?
In this project, you will build a team of three AI agents that collaborate to research any company and produce a tailored intelligence report for your job applications. You will deploy it as a live web app with a shareable URL anyone can visit.
What You'll Build
A multi-agent CrewAI system where three specialized AI agents work together to produce a company research brief, wrapped in a Streamlit web app and deployed to a live URL.
By the end of this project, you'll have:
- A fully configured multi-agent system with three AI agents that each have distinct roles, goals, and backstories.
- A sequential task pipeline where each agent builds on the previous agent's output to produce a polished research brief.
- A live deployed web app with a public URL you can share on your resume and in interviews.
- Secret Mission: Add a custom tool that scrapes a real job posting URL and feeds it into your crew for hyper-specific output.
Are there any prerequisites?
None. This guide walks you through installing every tool from scratch, including Python, the CrewAI CLI, and your free AI model provider. No prior AI or Python experience is required.
Install Python, uv, and CrewAI
Before you can build your AI agent crew, you need three tools on your machine.
Python is the programming language your agents run on. uv is a fast package manager that handles Python dependencies. CrewAI is the framework that turns your agents into a collaborative crew.
In this step, get ready to:
- Install uv on your machine.
- Install the CrewAI CLI using uv.
- Confirm Python 3.10 or higher is available.
Open your terminal
Every command in this step runs in your terminal (also called command line or shell).
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Terminal (macOS) or PowerShell (Windows) and press Enter to open it.
Install uv
uv is a fast Python package manager built by Astral. CrewAI uses it under the hood for dependency management, so you need it installed first.
- Install uv by running this command:
macOS
curl -LsSf https://astral.sh/uv/install.sh | sh
Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
What does this command do?
This downloads and runs the official uv installer from Astral's servers. It places the uv binary on your system and adds it to your PATH so you can use it from any terminal window.
If you are on Linux, use the same command shown in the macOS tab.
- Close and reopen your terminal so the PATH changes take effect.
- Verify uv is installed by running:
uv --version
✔️ I see a version number
uv is installed and ready to go.
ⓧ Command not found
The installer could not add uv to your PATH automatically. Run this command to fix it:
uv tool update-shell
Then close and reopen your terminal, and try uv --version again.
If it still does not work, ask for help debugging your uv installation.
Check your Python version
CrewAI requires Python 3.10 or higher (up to 3.13). The good news is that uv can automatically install Python for you if you do not already have a compatible version.
- Check which Python version you have by running:
macOS
python3 --version
Windows
python --version
✔️ I see version 3.10 or higher
Your Python version is compatible. You are ready to install CrewAI.
ⓧ I see a version lower than 3.10
You need a newer version of Python. Use uv to install Python 3.12 by running:
uv python install 3.12
Once complete, run the version check again to confirm you see 3.12 or higher.
ⓧ Command not found
Python is not installed on your machine. Use uv to install it by running:
uv python install 3.12
This downloads and installs Python 3.12 via uv's built-in Python management. Run the version check again to confirm it works.
Install the CrewAI CLI
The CrewAI CLI is a command-line tool that scaffolds new projects and runs your agent crews. You install it as a "tool" via uv, which keeps it available globally on your system.
- Install the CrewAI CLI by running:
uv tool install crewai
What does this command do?
uv tool install downloads the crewai package and makes its CLI commands available from any terminal session. It installs into an isolated environment so it does not interfere with other Python projects on your machine.
- Verify the installation succeeded by running:
uv tool list
You should see crewai listed in the output with a version number.
Don't see crewai in the list?
If the install succeeded but crewai does not appear, try running uv tool update-shell and reopening your terminal.
If the install itself failed, make sure you have an internet connection and that uv --version still works.
Help me troubleshoot my CrewAI CLI installation.
✔️ Awesome, I've got everything!
Great. You have uv, Python, and the CrewAI CLI ready to go.
ⓧ I'd like to double check
Run these three commands and confirm each produces output:
uv --version
python3 --version
uv tool list
You should see a uv version, a Python version of 3.10 or higher, and crewai in the tools list.
Your development environment is ready. Next up, you will scaffold your CrewAI project and connect it to a free AI model provider.
Create Your CrewAI Project and Set Up Groq
Your Python environment and CrewAI CLI are ready to go. Now it's time to create the actual project that will house your AI agent team.
CrewAI uses a specific folder structure to organize agents, tasks, and configuration. You will scaffold this structure with a single command, then connect it to Groq, a free LLM provider that powers your agents' thinking.
In this step, get ready to:
- Scaffold a new CrewAI project with the CLI.
- Sign up for a free Groq API key.
- Configure your project to use Groq as its LLM provider.
Scaffold your CrewAI project
The crewai create crew command generates an entire project skeleton for you. This includes YAML files for configuring agents, Python files for wiring logic, and a .env file for secrets.
- Move to your Desktop by running this command:
cd ~/Desktop
- Scaffold your CrewAI project by running this command:
crewai create crew job_research_crew
What will the CLI ask you?
The CLI will walk you through three interactive prompts:
- Select an LLM Provider - choose Groq from the list.
- Select a Model - pick any model listed (you will override this in .env shortly).
- Enter API Key - you can press Enter to skip this. You will add the key manually in a later substep.
The command takes a few seconds to finish. Once it completes, you should see a new job_research_crew folder on your Desktop.
- Move into your new project folder by running:
cd job_research_crew
- Confirm the project structure exists by running:
ls
You should see files like pyproject.toml, README.md, .env, and a src/ folder in the output.
What did CrewAI generate?
The scaffold created this folder structure for you:
- src/job_research_crew/config/agents.yaml - where you define your AI agents' personalities.
- src/job_research_crew/config/tasks.yaml - where you define what each agent does.
- src/job_research_crew/crew.py - where agents and tasks are wired together.
- src/job_research_crew/main.py - the entry point that kicks off your crew.
- .env - where you store API keys and model settings.
Don't see the folder?
- Make sure you ran the command from ~/Desktop. If you ran it elsewhere, check your current directory with pwd.
- If the CLI gave an error about the project name, make sure it is all lowercase with underscores (job_research_crew).
Help me troubleshoot my crewai create crew command
Now open the project in VS Code so you can edit files.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type VS Code and press Enter to open it.
- In VS Code, click File in the top menu bar.
- Click Open Folder.
- Navigate to your Desktop and select the job_research_crew folder, then click Open.
Sign up for a free Groq API key
Your agents need a brain to think with. Groq provides free access to powerful LLMs with no credit card required.
- Open console.groq.com in your browser.
- Sign up using your Google account, GitHub account, or email.
- Once you are logged in, click API Keys in the left sidebar.
- Click Create API Key.
- Give it a name like crewai-project and click Submit.
- Copy the API key immediately. It starts with gsk_ and will only be shown once.
Why Groq?
Groq runs models on custom hardware that delivers extremely fast inference. The free tier has no expiration date and no credit card requirement.
Your project will use Llama 3.3 70B, a highly capable open-source model. A single crew run uses only 3-6 API requests, well within the free tier limit of 1,000 requests per day.
Can't find the API Keys page?
After signing up, you should land on the Groq console dashboard. Look for API Keys in the left navigation panel. If you do not see it, make sure you are at console.groq.com and not the main marketing site.
Help me find where to create my Groq API key
Configure your project to use Groq
CrewAI reads its model and API key settings from the .env file in your project root. You will point it at Groq's Llama 3.3 70B model.
- In VS Code's Explorer sidebar, click on the .env file to open it.
- Delete everything in the file and replace it with this:
MODEL=groq/llama-3.3-70b-versatile
GROQ_API_KEY=your-groq-api-key-here
- Replace your-groq-api-key-here with the actual API key you copied from Groq (the one starting with gsk_).
What do these lines do?
- MODEL=groq/llama-3.3-70b-versatile tells CrewAI which LLM to use. The groq/ prefix routes requests through LiteLLM to Groq's API.
- GROQ_API_KEY authenticates your requests. CrewAI reads this automatically when it sees the groq/ prefix in the model name.
- Save the file with Cmd+S (macOS) or Ctrl+S (Windows).
Worried about committing your API key?
The .gitignore file that CrewAI generated already excludes .env from version control. Your key will not be pushed to GitHub.
Help me make sure my API key is safe
✔️ Awesome, I've got everything!
Great. Double check you have saved your .env file.
ⓧ I'd like to double check the full code
Here is what your .env file should look like:
MODEL=groq/llama-3.3-70b-versatile
GROQ_API_KEY=your-groq-api-key-here
Your project is scaffolded and connected to Groq. Next up, you will define the three specialized agents that make up your research crew.
Define Your Agent Team
Your CrewAI project is scaffolded and your Groq API key is configured. Now it's time to define the team of AI agents that will do the actual research work.
In CrewAI, each agent is a specialist defined by three YAML fields: role, goal, and backstory. You'll configure all three agents in this step and add the package that connects them to Groq.
In this step, get ready to:
- Configure three specialized agents in agents.yaml.
- Understand how role, goal, and backstory shape agent behaviour.
- Add the LiteLLM dependency so CrewAI can talk to Groq.
Configure your agent team in YAML
The scaffold created a default agents.yaml with placeholder content. You'll replace it with three agents that each have a specific job on your research crew.
- In VS Code, open src/job_research_crew/config/agents.yaml.
- Select all the existing content (Cmd+A on macOS or Ctrl+A on Windows) and replace it with the following:
company_researcher:
role: >
Senior Company Research Analyst
goal: >
Uncover comprehensive information about {company} including their mission,
recent news, tech stack, culture, and current challenges.
backstory: >
You are a meticulous research analyst who specializes in company intelligence.
You have a talent for finding the most relevant and recent information about
organizations, going beyond surface-level details to understand what truly
drives a company. You always verify your findings and present them in a
structured, actionable format.
role_analyst:
role: >
Career Strategy Analyst
goal: >
Analyze how a candidate's profile aligns with the {role} position at {company},
identifying key talking points and potential gaps to address.
backstory: >
You are a seasoned career strategist who has helped hundreds of professionals
land roles at top companies. You excel at connecting a candidate's experience
to what a company actually needs, finding angles that most applicants miss.
You think like a hiring manager and know what makes candidates stand out.
report_writer:
role: >
Professional Brief Writer
goal: >
Create a polished, actionable company research brief that prepares a candidate
for their application and interview at {company} for the {role} position.
backstory: >
You are an expert writer who creates executive-level briefing documents.
Your reports are clear, concise, and actionable. You distill complex research
into practical insights that help people make decisions and take action.
You structure information so readers can quickly find what they need.
What does this configuration do?
You just defined three specialists, each with a distinct personality:
- company_researcher gathers intelligence about the target company. Its goal mentions {company} so CrewAI injects the actual company name at runtime.
- role_analyst maps a candidate's strengths to the job requirements. It references both {company} and {role} so it can tailor its analysis.
- report_writer takes everything the other agents produce and distills it into a polished preparation brief.
How do role, goal, and backstory shape agent behaviour?
These three fields are not just labels. CrewAI injects them into the system prompt that powers each agent's LLM calls.
- Role tells the LLM what expertise to assume ("Senior Company Research Analyst").
- Goal focuses every decision the agent makes toward a specific outcome.
- Backstory adds personality and working style. A "meticulous" analyst behaves differently from a "creative" one.
The more specific these fields are, the better the output. Vague descriptions produce generic results.
- Save agents.yaml.
- You won't see output from these agents yet. The next step defines the tasks they'll work on.
Seeing a YAML error later when you run the crew?
- YAML is whitespace-sensitive. Make sure each role:, goal:, and backstory: key is indented with exactly two spaces under its agent name.
- The > character after each key means "fold this multi-line text into one paragraph." Do not remove it.
- Check that you have a blank line between each agent block (between company_researcher, role_analyst, and report_writer).
Why is my agents.yaml giving a parsing error when I run the crew?
✔️ Awesome, I've got everything!
Great. Double check you've saved agents.yaml before moving on.
ⓧ I'd like to double check the full code
Here is the complete agents.yaml file:
company_researcher:
role: >
Senior Company Research Analyst
goal: >
Uncover comprehensive information about {company} including their mission,
recent news, tech stack, culture, and current challenges.
backstory: >
You are a meticulous research analyst who specializes in company intelligence.
You have a talent for finding the most relevant and recent information about
organizations, going beyond surface-level details to understand what truly
drives a company. You always verify your findings and present them in a
structured, actionable format.
role_analyst:
role: >
Career Strategy Analyst
goal: >
Analyze how a candidate's profile aligns with the {role} position at {company},
identifying key talking points and potential gaps to address.
backstory: >
You are a seasoned career strategist who has helped hundreds of professionals
land roles at top companies. You excel at connecting a candidate's experience
to what a company actually needs, finding angles that most applicants miss.
You think like a hiring manager and know what makes candidates stand out.
report_writer:
role: >
Professional Brief Writer
goal: >
Create a polished, actionable company research brief that prepares a candidate
for their application and interview at {company} for the {role} position.
backstory: >
You are an expert writer who creates executive-level briefing documents.
Your reports are clear, concise, and actionable. You distill complex research
into practical insights that help people make decisions and take action.
You structure information so readers can quickly find what they need.
Add the LiteLLM dependency for Groq
CrewAI uses LiteLLM under the hood to route API requests to non-native providers like Groq. You need to declare this dependency in a requirements.txt file.
- Create a new file called requirements.txt in the root of your job_research_crew project folder (the same level as your .env file).
- Add the following content:
crewai[litellm]
streamlit
What do these dependencies do?
- crewai[litellm] installs CrewAI with the LiteLLM integration. The groq/ prefix in your MODEL environment variable tells LiteLLM to route requests to Groq's API.
- streamlit is the web framework you'll use later to give your crew a browser-based interface.
- Save requirements.txt.
- Confirm the file exists by running:
ls requirements.txt
You should see requirements.txt in the output.
✔️ Awesome, I've got everything!
Great. Double check you've saved requirements.txt before moving on.
ⓧ I'd like to double check the full code
Here is the complete requirements.txt file:
crewai[litellm]
streamlit
Your agent team is defined and your dependencies are ready. Next up, you'll design the task pipeline that tells each agent exactly what to do.
Design the Task Pipeline
Your agent team is defined. Each agent knows its role, goal, and backstory.
Now these agents need work to do. In CrewAI, a task is a specific job you assign to an agent. Each task has a description (what to do), an expected output (what success looks like), and an assigned agent (who does the work). You will define three tasks that form a sequential pipeline where each agent builds on the previous agent's output.
In this step, get ready to:
- Define three sequential tasks in tasks.yaml.
- Configure context passing between tasks.
- Set the final task to save output as a markdown file.
Define the research task
The first task in your pipeline gathers raw intelligence about a company. It tells the Company Researcher agent exactly what to look for and what format to deliver results in.
- In VS Code, open src/job_research_crew/config/tasks.yaml.
- Select all the scaffold content and delete it.
- Paste the following code to define your first task:
research_task:
description: >
Conduct comprehensive research on {company}. Find information about:
1. Company mission, values, and culture
2. Recent news and announcements (last 6 months)
3. Products and services they offer
4. Technology stack and engineering practices (if applicable)
5. Company size, funding stage, and growth trajectory
6. Key leadership team members
7. Current challenges or strategic priorities
Be thorough and focus on information that would help someone applying for
the {role} position understand the company deeply.
expected_output: >
A detailed research document with clearly labeled sections covering all
aspects of the company. Include specific facts, names, and dates where
possible. Flag any information that could be particularly relevant for
someone applying to the {role} position.
agent: company_researcher
What does this task definition do?
Every task in CrewAI has three required fields:
- description tells the agent exactly what to do. The more specific the instructions, the better the output.
- expected_output describes what success looks like. The agent uses this to judge when it has finished.
- agent assigns the task to one of your agents by name. This must match a key in agents.yaml.
Notice the {company} and {role} placeholders. CrewAI replaces these with real values when you run the crew, so the same task works for any company or role.
You won't see output yet. The next task builds on this one.
Seeing red squiggles in your YAML?
YAML is sensitive to indentation. Make sure each field (description, expected_output, agent) is indented with exactly 2 spaces under the task name.
The > symbol after a field means "multi-line text, fold into one paragraph." The text lines below it must be indented further (4 spaces from the left edge).
help me fix YAML indentation errors in my tasks.yaml file
Add the analysis task with context
The second task takes the research output and turns it into strategic advice. This is where context passing comes in. You will tell this task to read the output of the research task before starting its own work.
- In tasks.yaml, add the following code directly below the research_task block (leave one blank line between them):
analysis_task:
description: >
Based on the company research provided, analyze how a candidate should
position themselves for the {role} position at {company}. Specifically:
1. Identify the top 5 skills and experiences that would matter most for this role
2. Suggest 3 talking points that would resonate with the hiring team
3. Identify potential culture-fit signals to emphasize
4. Note any red flags or challenges the candidate should be prepared to discuss
5. Recommend specific questions the candidate should ask in an interview
expected_output: >
A strategic analysis document with actionable recommendations for the
candidate. Each recommendation should be specific and tied back to something
discovered in the company research. Include a priority ranking for preparation topics.
agent: role_analyst
context:
- research_task
What does the context field do?
The context field is what makes this a pipeline instead of three isolated tasks. It tells CrewAI to pass the output of research_task directly into this task as input.
Think of it like a relay race. The Company Researcher finishes its research and hands the baton (its output) to the Role Analyst. The Role Analyst reads that research and builds its analysis on top of it.
You still won't see visible output. The final task completes the pipeline.
Complete the pipeline with the report task
The final task takes both the raw research and the strategic analysis, then produces a polished brief. It receives context from both previous tasks and saves its output to a markdown file.
- Add the following code below the analysis_task block (leave one blank line between them):
report_task:
description: >
Using the company research and strategic analysis, create a polished
company research brief for a candidate applying to the {role} position
at {company}. The brief should be formatted as a professional document
with the following sections:
1. Executive Summary (2-3 sentences)
2. Company Overview
3. Role Alignment Analysis
4. Key Talking Points (with supporting evidence)
5. Preparation Checklist
6. Recommended Interview Questions to Ask
Make the brief actionable and easy to scan before an interview.
expected_output: >
A well-formatted markdown document that serves as a complete preparation
brief for the candidate. It should be professional enough to share with
a career coach and practical enough to review 30 minutes before an interview.
agent: report_writer
context:
- research_task
- analysis_task
output_file: output/report.md
What's different about this task?
This task has two new features compared to the previous tasks:
- context lists both research_task and analysis_task. The Report Writer gets access to everything produced so far.
- output_file: output/report.md saves the final report to a file on disk. This gives you a permanent artifact you can open, share, or reference later.
- Save tasks.yaml.
Not sure if your YAML is correct?
Check these common issues:
- Each task name (research_task, analysis_task, report_task) must start at column 0 with no leading spaces.
- The context items must use a dash and a space (- research_task), indented 4 spaces from the left edge.
- Make sure the agent values exactly match the agent names in agents.yaml.
help me debug my tasks.yaml file
✔️ Awesome, I've got everything!
Great. Double check you've saved tasks.yaml and move on to the next step.
ⓧ I'd like to double check the full code
Here is the complete tasks.yaml file. Compare yours against this:
research_task:
description: >
Conduct comprehensive research on {company}. Find information about:
1. Company mission, values, and culture
2. Recent news and announcements (last 6 months)
3. Products and services they offer
4. Technology stack and engineering practices (if applicable)
5. Company size, funding stage, and growth trajectory
6. Key leadership team members
7. Current challenges or strategic priorities
Be thorough and focus on information that would help someone applying for
the {role} position understand the company deeply.
expected_output: >
A detailed research document with clearly labeled sections covering all
aspects of the company. Include specific facts, names, and dates where
possible. Flag any information that could be particularly relevant for
someone applying to the {role} position.
agent: company_researcher
analysis_task:
description: >
Based on the company research provided, analyze how a candidate should
position themselves for the {role} position at {company}. Specifically:
1. Identify the top 5 skills and experiences that would matter most for this role
2. Suggest 3 talking points that would resonate with the hiring team
3. Identify potential culture-fit signals to emphasize
4. Note any red flags or challenges the candidate should be prepared to discuss
5. Recommend specific questions the candidate should ask in an interview
expected_output: >
A strategic analysis document with actionable recommendations for the
candidate. Each recommendation should be specific and tied back to something
discovered in the company research. Include a priority ranking for preparation topics.
agent: role_analyst
context:
- research_task
report_task:
description: >
Using the company research and strategic analysis, create a polished
company research brief for a candidate applying to the {role} position
at {company}. The brief should be formatted as a professional document
with the following sections:
1. Executive Summary (2-3 sentences)
2. Company Overview
3. Role Alignment Analysis
4. Key Talking Points (with supporting evidence)
5. Preparation Checklist
6. Recommended Interview Questions to Ask
Make the brief actionable and easy to scan before an interview.
expected_output: >
A well-formatted markdown document that serves as a complete preparation
brief for the candidate. It should be professional enough to share with
a career coach and practical enough to review 30 minutes before an interview.
agent: report_writer
context:
- research_task
- analysis_task
output_file: output/report.md
Why sequential instead of parallel?
CrewAI supports both sequential and parallel task execution. In this project, each task depends on the output of the previous one. The Role Analyst cannot analyze alignment without first having the company research. The Report Writer cannot write a brief without both the research and the analysis.
Sequential pipelines are simpler to debug and reason about. If the final report is off, you can trace the problem to a specific task in the chain.
Your task pipeline is designed. Next up, you will wire these tasks to your agents in Python and run the crew for the first time.
Wire Up the Crew and Run It Locally
Your agents have their personalities and your tasks have their instructions. Now you need to connect everything together so the agents actually execute the tasks in order.
CrewAI uses a Python class decorated with @CrewBase to wire agents and tasks together. You will update two files: crew.py (which defines who does what) and main.py (which kicks the whole crew off). Then you will run the crew and watch your agents collaborate in real time.
In this step, get ready to:
- Update crew.py to connect your agents and tasks via the @CrewBase decorator pattern.
- Configure main.py with input variables for the company and target role.
- Install dependencies and run the crew to generate your first research report.
Update crew.py with the @CrewBase pattern
The @CrewBase decorator is what makes CrewAI automatically load your YAML config files and connect them to your Python methods. Each method decorated with @agent or @task maps to an entry in your YAML.
- In VS Code, open src/job_research_crew/crew.py.
- Select all the existing scaffold content and replace it with the following code:
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
@CrewBase
class JobResearchCrew():
"""Job Research Crew for company intelligence and application preparation"""
agents: List[BaseAgent]
tasks: List[Task]
@agent
def company_researcher(self) -> Agent:
return Agent(
config=self.agents_config['company_researcher'], # type: ignore[index]
verbose=True
)
@agent
def role_analyst(self) -> Agent:
return Agent(
config=self.agents_config['role_analyst'], # type: ignore[index]
verbose=True
)
@agent
def report_writer(self) -> Agent:
return Agent(
config=self.agents_config['report_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 analysis_task(self) -> Task:
return Task(
config=self.tasks_config['analysis_task'] # type: ignore[index]
)
@task
def report_task(self) -> Task:
return Task(
config=self.tasks_config['report_task'] # type: ignore[index]
)
@crew
def crew(self) -> Crew:
"""Creates the Job Research Crew"""
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,
verbose=True,
)
What does this code do?
The @CrewBase decorator tells CrewAI to automatically load agents.yaml and tasks.yaml from the config/ folder. It populates self.agents_config and self.tasks_config dictionaries with your YAML content.
- Each @agent method creates an agent using the matching key from agents.yaml. The method name must match the YAML key exactly.
- Each @task method creates a task using the matching key from tasks.yaml. CrewAI uses the YAML context and agent fields to wire up dependencies automatically.
- The @crew method assembles everything. Process.sequential means agents run one after the other, passing output forward.
- Save crew.py.
Seeing red underlines in VS Code?
Your editor may show import errors because the dependencies are not installed yet. This is normal. You will install them in the final substep of this step.
help me understand why VS Code shows import errors before I install packages
Configure main.py with your target company and role
The main.py file is the entry point that CrewAI calls when you run crewai run. It defines the input variables (company name and target role) that get injected into your YAML templates wherever you wrote {company} and {role}.
- Open src/job_research_crew/main.py.
- Select all the existing scaffold content and replace it with the following code:
#!/usr/bin/env python
import os
from job_research_crew.crew import JobResearchCrew
# Create output directory if it doesn't exist
os.makedirs('output', exist_ok=True)
def run():
"""
Run the Job Research Crew.
"""
inputs = {
'company': 'Flipkart',
'role': 'Software Engineer'
}
# Create and run the crew
result = JobResearchCrew().crew().kickoff(inputs=inputs)
print("\n\n========================")
print("## Research Brief Generated")
print("========================\n")
print(result.raw)
print("\n\nReport saved to: output/report.md")
What does this code do?
- os.makedirs('output', exist_ok=True) creates the output/ folder if it does not already exist. This is where your final report lands.
- The inputs dictionary provides values for every {company} and {role} placeholder in your YAML files. You can change these to any company and role you like.
- .kickoff(inputs=inputs) starts the sequential pipeline. Each agent receives the inputs, does its work, and passes its output to the next task via the context field you configured.
- Save main.py.
Research a different company
Feel free to replace Flipkart and Software Engineer with any company and role you are actually interested in. The agents will tailor the entire report to whatever you enter.
Install dependencies and run the crew
CrewAI manages its own virtual environment. The crewai install command reads your pyproject.toml and installs all required packages into that environment.
- Install your project dependencies by running this command:
crewai install
- You should see output showing packages being resolved and installed. This may take 1-2 minutes.
Command not found?
If your terminal does not recognize crewai, run uv tool update-shell and then open a new terminal window. This refreshes your PATH so the shell can find the CrewAI CLI.
help me fix crewai command not found after installing with uv
- Run your crew by running this command:
crewai run
Your terminal will fill with live agent output. You will see each agent thinking, researching, and writing in real time. The full run takes 1-3 minutes depending on your network speed.
What should I see?
You will see log lines showing each agent's name, the task it is working on, and its reasoning process. At the end, a formatted research brief prints to the terminal and gets saved to output/report.md.
The final lines should say Research Brief Generated followed by the full markdown report.
- Confirm the report was saved by running:
ls output/
- You should see report.md in the output.
Seeing a rate limit or authentication error?
- Double check that your .env file has GROQ_API_KEY set to your actual key (starting with gsk_).
- Verify MODEL is set to groq/llama-3.3-70b-versatile with no extra spaces.
- If you hit rate limits, wait 60 seconds and run crewai run again. The free tier allows 30 requests per minute.
help me fix my CrewAI crew failing with a Groq API error
✔️ Awesome, I've got everything!
Great. Double check you have saved both crew.py and main.py.
ⓧ I'd like to double check the full code
Here is the full crew.py:
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
@CrewBase
class JobResearchCrew():
"""Job Research Crew for company intelligence and application preparation"""
agents: List[BaseAgent]
tasks: List[Task]
@agent
def company_researcher(self) -> Agent:
return Agent(
config=self.agents_config['company_researcher'], # type: ignore[index]
verbose=True
)
@agent
def role_analyst(self) -> Agent:
return Agent(
config=self.agents_config['role_analyst'], # type: ignore[index]
verbose=True
)
@agent
def report_writer(self) -> Agent:
return Agent(
config=self.agents_config['report_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 analysis_task(self) -> Task:
return Task(
config=self.tasks_config['analysis_task'] # type: ignore[index]
)
@task
def report_task(self) -> Task:
return Task(
config=self.tasks_config['report_task'] # type: ignore[index]
)
@crew
def crew(self) -> Crew:
"""Creates the Job Research Crew"""
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,
verbose=True,
)
Here is the full main.py:
#!/usr/bin/env python
import os
from job_research_crew.crew import JobResearchCrew
# Create output directory if it doesn't exist
os.makedirs('output', exist_ok=True)
def run():
"""
Run the Job Research Crew.
"""
inputs = {
'company': 'Flipkart',
'role': 'Software Engineer'
}
# Create and run the crew
result = JobResearchCrew().crew().kickoff(inputs=inputs)
print("\n\n========================")
print("## Research Brief Generated")
print("========================\n")
print(result.raw)
print("\n\nReport saved to: output/report.md")
Your agents just collaborated on their first report. Next up, you will wrap this crew in a web interface so anyone can run it from a browser.
Add a Streamlit Web Interface
Your agents work perfectly from the terminal, but right now you are the only person who can use them. A web interface lets anyone interact with your crew without touching the command line.
Streamlit is a Python framework that turns scripts into web apps with just a few lines of code. You will create a single app.py file that gives your crew a visual front end with input fields, a progress display, and a download button.
In this step, get ready to:
- Create an app.py file with a Streamlit UI that has input fields for company and role.
- Wire the Streamlit app to trigger your crew and display the generated report.
- Test the web app locally and confirm it works in your browser.
Create the app.py UI layout
Your Streamlit app needs a page title, a description, and two input fields where users type a company name and a target role. You will put all of this in a new file at the project root.
- Create a new file called app.py in the root of your job_research_crew project folder (the same level as your .env file).
- Add the following code to set up the page layout and input fields:
import streamlit as st
import os
from src.job_research_crew.crew import JobResearchCrew
# Configure the page title, icon, and layout
st.set_page_config(page_title="AI Job Research Crew", page_icon="\ud83e\udd16", layout="wide")
# Display the app header and description
st.title("\ud83e\udd16 AI Job Research Crew")
st.markdown("Three AI agents collaborate to research a company and prepare you for your job application.")
# Create a two-column layout for the input fields
col1, col2 = st.columns(2)
with col1:
company = st.text_input("Company Name", placeholder="e.g. Flipkart, Razorpay, Google")
with col2:
role = st.text_input("Target Role", placeholder="e.g. Software Engineer, Data Scientist")
What does this code do?
The import at the top pulls in your JobResearchCrew class so the web app can trigger your agents directly.
st.set_page_config sets the browser tab title and page icon. st.columns(2) places the two input fields side by side so the app looks clean on wide screens.
You will not see a change yet because the file needs the button handler to be runnable.
Wire the button handler to your crew
When a user clicks the button, the app needs to validate the inputs, show progress messages while agents work, and then display the final report with a download option.
- Add the following code directly below the input fields in app.py:
if st.button("\ud83d\ude80 Run Research Crew", type="primary"):
# Validate that both fields have values
if not company or not role:
st.warning("Please enter both a company name and a target role.")
else:
# Show a status container while agents work
with st.status("AI Agents are working...", expanded=True) as status:
st.write("\ud83d\udd0d **Company Researcher** is gathering intelligence...")
st.write("\ud83d\udcca **Role Analyst** is mapping skills to requirements...")
st.write("\u270d\ufe0f **Report Writer** is creating your brief...")
# Run the crew with user inputs
os.makedirs('output', exist_ok=True)
inputs = {'company': company, 'role': role}
result = JobResearchCrew().crew().kickoff(inputs=inputs)
status.update(label="Research complete!", state="complete", expanded=False)
# Display the generated report
st.markdown("---")
st.markdown("## \ud83d\udccb Your Company Research Brief")
st.markdown(result.raw)
# Offer a download button for the report
st.download_button(
label="\ud83d\udce5 Download Report as Markdown",
data=result.raw,
file_name=f"{company.lower().replace(' ', '_')}_research_brief.md",
mime="text/markdown"
)
What does this code do?
st.button creates a clickable button. When pressed, Streamlit reruns the script and enters the if block.
st.status creates an expandable container that shows progress messages while your crew runs. After kickoff() finishes, status.update collapses the container and marks it complete.
st.download_button renders a button that lets users save the report as a .md file to their computer.
- Save app.py.
Seeing a red underline on the import?
If VS Code shows a warning on from src.job_research_crew.crew import JobResearchCrew, this is normal. The import resolves correctly at runtime because you run the app from the project root.
help me fix import warnings in my Streamlit app
✔️ Awesome, I've got everything!
Great. Make sure you have saved app.py before moving on.
ⓧ I'd like to double check the full code
Here is the complete app.py file. Compare yours against it:
import streamlit as st
import os
from src.job_research_crew.crew import JobResearchCrew
st.set_page_config(page_title="AI Job Research Crew", page_icon="\ud83e\udd16", layout="wide")
st.title("\ud83e\udd16 AI Job Research Crew")
st.markdown("Three AI agents collaborate to research a company and prepare you for your job application.")
col1, col2 = st.columns(2)
with col1:
company = st.text_input("Company Name", placeholder="e.g. Flipkart, Razorpay, Google")
with col2:
role = st.text_input("Target Role", placeholder="e.g. Software Engineer, Data Scientist")
if st.button("\ud83d\ude80 Run Research Crew", type="primary"):
if not company or not role:
st.warning("Please enter both a company name and a target role.")
else:
with st.status("AI Agents are working...", expanded=True) as status:
st.write("\ud83d\udd0d **Company Researcher** is gathering intelligence...")
st.write("\ud83d\udcca **Role Analyst** is mapping skills to requirements...")
st.write("\u270d\ufe0f **Report Writer** is creating your brief...")
os.makedirs('output', exist_ok=True)
inputs = {'company': company, 'role': role}
result = JobResearchCrew().crew().kickoff(inputs=inputs)
status.update(label="Research complete!", state="complete", expanded=False)
st.markdown("---")
st.markdown("## \ud83d\udccb Your Company Research Brief")
st.markdown(result.raw)
st.download_button(
label="\ud83d\udce5 Download Report as Markdown",
data=result.raw,
file_name=f"{company.lower().replace(' ', '_')}_research_brief.md",
mime="text/markdown"
)
Test your web app locally
Streamlit includes a built-in development server that launches your app in a browser tab.
- Launch the Streamlit app by running this command from your project root:
streamlit run app.py
- A new browser tab opens automatically at http://localhost:8501.
- You should see the title, a description line, and two input fields for company and role.
- Type a company name (e.g. Google) and a role (e.g. Software Engineer), then click the blue button.
- Wait for the agents to finish. This takes 30-90 seconds depending on Groq response times.
- Once complete, a formatted research brief appears below the button with a download option.
What should I see?
While agents work, you see an expanded status box with three progress messages. When the crew finishes, the status box collapses and shows a green checkmark. The full report renders as formatted markdown below a horizontal line.
App not loading or showing an error?
- Make sure you are running the command from the project root folder (the one containing app.py and .env).
- If you see a ModuleNotFoundError, confirm your virtual environment is active and that you ran crewai install in a previous step.
- If the crew times out or returns an error, check that your .env file has a valid GROQ_API_KEY value.
help me debug my Streamlit CrewAI app
- Press Ctrl+C in the terminal to stop the Streamlit server when you are done testing.
Your agents now have a proper web interface that anyone on your machine can use. Next up, you will deploy this app to a live URL that anyone on the internet can visit.
Deploy to Streamlit Community Cloud
Your app works locally. Now it is time to put it on the internet so anyone can use it.
In this step, you will push your code to GitHub and deploy it to Streamlit Community Cloud. The result is a live URL (like yourapp.streamlit.app) that you can share with anyone.
In this step, get ready to:
- Push your project to a public GitHub repository.
- Connect your repo to Streamlit Community Cloud and deploy.
- Add your GROQ_API_KEY as a secret and verify the live URL works.
Push your project to GitHub
Streamlit Community Cloud deploys directly from a GitHub repository. You need your code in a public repo so the platform can pull it.
- Open your browser and go to github.com/new to create a new repository.
- Enter job-research-crew as the repository name.
- Set the visibility to Public.
- Do NOT check any of the initialization options (no README, no .gitignore, no license).
- Click Create repository.
GitHub shows you a quick setup page with commands. Now initialize your local project as a Git repo and push it.
- Before pushing, make sure your .env file is in .gitignore so your API key does not get committed. Open .gitignore in VS Code and confirm it contains .env. If not, add it.
- Also add .streamlit/ to your .gitignore so your secrets file stays local.
- Push your code to GitHub by running these commands in your terminal:
git init
git add .
git commit -m "Initial commit"
git branch -M main
git remote add origin https://github.com/[[GITHUB_USERNAME="your-github-username"]]/job-research-crew.git
git push -u origin main
What do these commands do?
- git init turns your project folder into a Git repository.
- git add . stages all files (except those in .gitignore) for commit.
- git push -u origin main uploads your code to the GitHub repository you just created.
- Refresh your GitHub repository page in the browser. You should see all your project files listed.
Push failed or permission denied?
- Make sure you replaced the GitHub username in the remote URL with your actual username.
- If you see an authentication error, you may need to set up a personal access token or SSH key for GitHub.
- help me push my code to GitHub
Create your secrets file for Streamlit
Streamlit Community Cloud reads secrets from a special .streamlit/secrets.toml file. You will create this file locally so Streamlit can find your API key when deployed.
- Create the .streamlit directory and the secrets file by running:
mkdir -p .streamlit
touch .streamlit/secrets.toml
- Open .streamlit/secrets.toml in VS Code and add the following content:
GROQ_API_KEY = "your-groq-api-key-here"
MODEL = "groq/llama-3.3-70b-versatile"
- Replace your-groq-api-key-here with your actual Groq API key (the one starting with gsk_).
Why a separate secrets file?
Your .env file works for local development with CrewAI. The .streamlit/secrets.toml file is what Streamlit Community Cloud uses to inject environment variables into your deployed app. You need both, but neither gets committed to GitHub.
- Confirm .streamlit/ is in your .gitignore (you added it earlier). This file must never be pushed to GitHub.
Deploy to Streamlit Community Cloud
Streamlit Community Cloud is a free hosting platform for Streamlit apps. It connects to your GitHub repo and deploys your app automatically.
- Go to share.streamlit.io in your browser.
- Click Continue to sign-in.
- Click Continue with GitHub and sign in with your GitHub credentials.
- Fill in your account information if prompted, then click I accept or Continue at the bottom.
What is Streamlit Community Cloud?
Streamlit Community Cloud is a free platform that deploys Streamlit apps directly from GitHub repositories. Every time you push code to your repo, it automatically updates your deployed app.
- After signing in, you need to connect your GitHub account. From the Workspaces dropdown, click Connect GitHub account.
- Follow GitHub's authentication prompts and click Authorize streamlit.
- In the upper-right corner, click Create app.
- When asked if you already have an app, click Yup, I have an app.
- In the Repository field, select or type your job-research-crew repository.
- In the Branch field, enter main.
- In the Main file path field, enter app.py.
Before deploying, you need to add your secrets so the deployed app can access Groq.
- Click Advanced settings.
- In the Secrets text area, paste the contents of your .streamlit/secrets.toml file:
GROQ_API_KEY = "your-groq-api-key-here"
MODEL = "groq/llama-3.3-70b-versatile"
- Replace your-groq-api-key-here with your actual Groq API key.
- Click Save.
- Click Deploy.
What happens during deployment?
Streamlit Community Cloud pulls your code from GitHub, installs the packages listed in requirements.txt, and starts your app. Most deployments finish within a few minutes. You can watch the logs on the right side of the screen.
- Wait for the deployment to complete. You will see your app load at a URL like yourname-job-research-crew-app-xxxxx.streamlit.app.
- Test your deployed app by entering a company name and role, then clicking the run button.
- Verify that the research report generates successfully. This confirms your secrets are configured correctly and the app is live.
App crashing or showing errors?
- Check the deployment logs on the right side of the screen for specific error messages.
- If you see a module not found error, make sure requirements.txt is in the root of your repository and contains crewai[litellm] and streamlit.
- If the app loads but the crew fails to run, confirm your GROQ_API_KEY secret is correct in the app settings. Go to your app's menu and click Settings, then check the Secrets section.
- help me debug my Streamlit deployment
✔️ Awesome, I've got everything!
Great. Double check you have saved all your files and your app is live at its .streamlit.app URL.
ⓧ I'd like to double check the full code
Here is the complete .streamlit/secrets.toml file you should have:
GROQ_API_KEY = "your-groq-api-key-here"
MODEL = "groq/llama-3.3-70b-versatile"
And your app.py should still match this:
import streamlit as st
import os
from src.job_research_crew.crew import JobResearchCrew
st.set_page_config(page_title="AI Job Research Crew", page_icon="🤖", layout="wide")
st.title("🤖 AI Job Research Crew")
st.markdown("Three AI agents collaborate to research a company and prepare you for your job application.")
col1, col2 = st.columns(2)
with col1:
company = st.text_input("Company Name", placeholder="e.g. Flipkart, Razorpay, Google")
with col2:
role = st.text_input("Target Role", placeholder="e.g. Software Engineer, Data Scientist")
if st.button("🚀 Run Research Crew", type="primary"):
if not company or not role:
st.warning("Please enter both a company name and a target role.")
else:
with st.status("AI Agents are working...", expanded=True) as status:
st.write("🔍 **Company Researcher** is gathering intelligence...")
st.write("📊 **Role Analyst** is mapping skills to requirements...")
st.write("✍️ **Report Writer** is creating your brief...")
os.makedirs('output', exist_ok=True)
inputs = {'company': company, 'role': role}
result = JobResearchCrew().crew().kickoff(inputs=inputs)
status.update(label="Research complete!", state="complete", expanded=False)
st.markdown("---")
st.markdown("## 📋 Your Company Research Brief")
st.markdown(result.raw)
st.download_button(
label="📥 Download Report as Markdown",
data=result.raw,
file_name=f"{company.lower().replace(' ', '_')}_research_brief.md",
mime="text/markdown"
)
Your requirements.txt should contain:
crewai[litellm]
streamlit
Your multi-agent AI system is now live on the internet. Anyone with the link can use your agents to research companies. Next up, you will tackle a Secret Mission to extend your crew with a custom tool.
Clean Up Your Resources
Clean Up Your Resources
This project uses the Groq free tier and Streamlit Community Cloud, so there are no ongoing costs. Your Streamlit app automatically hibernates after 12 hours without traffic.
Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Resources you used:
- Local project files (job_research_crew folder on your Desktop).
- CrewAI CLI tool (installed via uv).
- Streamlit Community Cloud app (your live deployed URL).
- GitHub repository (job_research_crew).
- Groq API key (stored at console.groq.com).
Keep everything running
No action needed. Choose this if you are still actively building or want your Streamlit app to stay live.
- Your Streamlit app stays accessible at its public URL. It hibernates automatically after 12 hours without visitors and wakes up when someone visits again.
- Your Groq API key remains active. The free tier has no expiration date, so there is nothing to renew.
- The uv package manager remains installed on your machine. It has no documented uninstall command, so it stays unless you manually remove the binary.
Pause - I'll come back to this later
Shut down your live app to free up your Streamlit Community Cloud slot, but keep your local files and GitHub repo intact so you can redeploy later.
- Go to your Streamlit workspace at share.streamlit.io.
- Find your app in the list and click the overflow menu (three dots icon) to the right of it.
- Select Delete to remove the deployed app. Your code on GitHub is unaffected.
- Keep your local job_research_crew folder and GitHub repository. When you are ready to return, redeploy from Streamlit Community Cloud.
Delete - I don't want to use this again
Remove all project resources and start fresh. Follow each item below.
- Delete your Streamlit Community Cloud app. Go to share.streamlit.io, click the overflow menu (three dots) next to your app, and select Delete.
- Delete your GitHub repository. Open your repository on GitHub, click Settings, scroll to the Danger Zone section, and click Delete this repository. Confirm by typing the repository name.
- Revoke your Groq API key. Go to console.groq.com, navigate to your API Keys page, and delete the key you created for this project.
- Uninstall the CrewAI CLI by running:
- Delete your local project files by running:
uv tool uninstall crewai
Remove your local project folder (macOS/Linux):
rm -rf ~/Desktop/job_research_crew
On Windows, run this in PowerShell instead:
Remove-Item -Recurse -Force ~\Desktop\job_research_crew
That's a Wrap!
That's a Wrap!
Nice work! You just built and deployed a production-style multi-agent AI system with a live public URL.
Here's what you accomplished:
- Built a multi-agent system with three specialized CrewAI agents that collaborate using sequential task orchestration and context passing.
- Configured agents with roles, goals, and backstories in YAML and designed a task pipeline where each agent builds on the previous agent's output.
- Deployed a Streamlit web app to a live public URL on Streamlit Community Cloud that anyone can visit to see your agents in action.
- Built a custom scraper tool that fetches real job posting data and feeds it into your agents for hyper-specific output.
Ready to quiz yourself?