AI Code Reviewer with Python and Gemini
Build a CLI tool that uses Gemini AI to review any source code file.
Introduction
30 Second Summary
Code reviews are how developers catch bugs and improve quality before code ships. But getting timely feedback often means waiting for a teammate to be free.
In this project, you will build a command-line Python tool that sends source code to Google's Gemini AI and returns structured review feedback covering bugs, improvements, and style issues.
What You'll Build
A Python CLI tool that reads any source code file, sends it to the Gemini API with a "senior code reviewer" system prompt, and prints structured feedback.
By the end of this project, you'll have:
- A configured Python development environment with VS Code and virtual environments.
- A working AI-powered code reviewer that analyzes any file for bugs, improvements, and style issues.
- Practical experience calling an LLM API with system instructions and processing structured responses.
- Secret Mission: Extend the tool to review multiple files at once and generate a markdown report.
Are there any prerequisites?
You need basic programming knowledge in any language and a Google account. You should also have Python 3 installed on your machine. No prior AI or API experience is required.
Set Up Your Environment
Before you can build an AI-powered code reviewer, you need a proper development environment. This means a code editor, a Python project folder with isolated dependencies, and an API key to talk to Gemini.
In this step, you will install VS Code, create a Python project with a virtual environment, and connect to Google's Gemini API. Once this is done, you will have everything you need to start writing the reviewer script.
In this step, get ready to:
- Install VS Code and the Python extension.
- Create a project folder with a virtual environment.
- Get your free Gemini API key.
Install VS Code and the Python extension
VS Code is a free code editor that gives you syntax highlighting, a built-in terminal, and extensions for Python development.
- Open your browser and go to https://code.visualstudio.com/.
- Click the download button for your operating system.
- Run the installer and follow the prompts to complete installation.
- Open VS Code by pressing Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Visual Studio Code and press Enter to open it.
Now install the Python extension so VS Code understands Python files.
- Open the Extensions panel by pressing Cmd+Shift+X (macOS) or Ctrl+Shift+X (Windows).
- Type Python in the search bar.
- Find the extension published by Microsoft and click Install.
Next, open the integrated terminal so you can run commands directly inside VS Code.
- Press Cmd+` (macOS) or Ctrl+` (Windows) to open the terminal panel. The backtick key is next to the 1 key on your keyboard.
- Verify Python is accessible by running this command:
python3 --version
✔️ I see a version number
You should see something like Python 3.x.x printed in the terminal. Python is ready to go.
ⓧ Command not found
If you see an error, Python may not be installed or not added to your system PATH.
- Go to https://www.python.org/downloads/ and download the latest version of Python 3.
- Run the installer. On Windows, make sure to check the Add Python to PATH box before clicking Install Now.
- Close and reopen VS Code, then try python3 --version again in the terminal.
Windows users
On Windows, the command might be python --version instead of python3 --version. Try both to see which one works.
Create a project folder with a virtual environment
A virtual environment is an isolated Python workspace. It keeps this project's packages separate from your system Python, so nothing conflicts.
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and move into it by running these commands:
mkdir ai-code-reviewer
cd ai-code-reviewer
- Confirm the folder exists by running:
ls
You should see ai-code-reviewer listed in the output.
Now open this folder in VS Code so the editor recognizes it as your workspace.
- In VS Code, click File in the top menu bar.
- Click Open Folder.
- Navigate to your Desktop and select the ai-code-reviewer folder, then click Open.
Why open the folder?
Opening a folder in VS Code tells the editor where your project lives. The integrated terminal will start in that folder, and the sidebar will show your project files.
- Open a new terminal in VS Code by pressing Cmd+` (macOS) or Ctrl+` (Windows). This terminal now starts inside ai-code-reviewer.
- Create a virtual environment by running this command:
python3 -m venv venv
What does this command do?
The python3 -m venv venv command creates a folder called venv inside your project. This folder contains a standalone copy of Python and a place to install packages without affecting anything else on your machine.
- Activate the virtual environment by running the command for your operating system:
macOS
source venv/bin/activate
Windows
venv\Scripts\activate
You should see (venv) appear at the beginning of your terminal prompt. This confirms the virtual environment is active.
Don't see (venv) in your prompt?
On Windows, you may need to allow script execution first. Run Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned in PowerShell, then try the activate command again.
On macOS, make sure you typed source before the path. Without it, the shell will not run the activation script.
Help me activate my virtual environment.
- Install the Google Gen AI SDK by running:
pip install google-genai
What is google-genai?
The google-genai package is Google's official Python SDK for the Gemini API. It handles authentication, request formatting, and response parsing so you can call the AI model with just a few lines of Python.
- Verify the installation worked by running:
python3 -c "from google import genai; print('SDK ready')"
You should see SDK ready printed in your terminal.
Don't see SDK ready?
Make sure your virtual environment is active (you should see (venv) in your prompt). If not, re-run the activation command above.
If you see a ModuleNotFoundError, try running pip install google-genai again.
Help me debug this issue.
Get your free Gemini API key
To call the Gemini AI model, you need an API key. Google provides a free tier for the Gemini API, so this costs nothing.
- Open https://aistudio.google.com/apikey in your browser.
- Sign in with your Google account if prompted.
- Click Create API Key.
- Select an existing Google Cloud project or create a new one when prompted.
- Copy the API key that appears. Keep it somewhere safe. You will not be able to see it again after closing this dialog.
What is an API key?
An API key is a unique string that identifies your requests to a service. Think of it like a library card. The library (Google) needs to know who is making requests so it can track usage and enforce limits.
The Gemini free tier gives you free input and output tokens, so you can experiment without spending anything.
Now set the key as an environment variable so your Python script can read it without hardcoding it in your code.
- In the VS Code terminal, set the environment variable by running the command for your operating system:
macOS
export GEMINI_API_KEY="your-api-key-here"
- Replace your-api-key-here with the key you just copied from Google AI Studio.
Windows
$Env:GEMINI_API_KEY = "your-api-key-here"
- Replace your-api-key-here with the key you just copied from Google AI Studio.
Why use an environment variable?
Storing secrets in environment variables keeps them out of your source code. The google-genai SDK automatically reads GEMINI_API_KEY from your environment, so you never need to paste the key into your Python files.
- Verify the key works by running this command:
python3 -c "from google import genai; client = genai.Client(); print('Connected')"
You should see Connected printed in your terminal. This confirms the SDK can reach Google's servers using your API key.
Seeing an authentication error?
Double check that you pasted the full API key with no extra spaces. Make sure the quotes around the key are straight quotes, not curly quotes.
If you closed and reopened the terminal, you need to re-run the export (macOS) or $Env: (Windows) command. Environment variables only last for the current terminal session.
Help me fix this authentication error.
Keep this terminal open
Your environment variable is set for this terminal session only. If you close the terminal, you will need to set GEMINI_API_KEY again. Keep this terminal open for the rest of the project.
Your development environment is fully set up. Next up, you will write the code reviewer script that reads a file and sends it to Gemini for AI-powered feedback.
Build the Code Reviewer
Your environment is ready with Python, the Gemini SDK, and a valid API key. Now it's time to write the actual tool.
Every AI-powered CLI tool follows the same pattern: read input, send it to a model with instructions, and display the response. In this step, you'll build reviewer.py to do exactly that.
In this step, get ready to:
- Create the script skeleton with argument validation.
- Add a function that reads source code files.
- Wire up the Gemini API call with a code reviewer system prompt.
Create the main script structure
Before the script can review code, it needs to handle the basics: accept a filename from the command line and verify the file exists. This prevents confusing errors later when the script tries to read a file that isn't there.
- In VS Code, create a new file called reviewer.py in your ai-code-reviewer folder.
- Paste the following code into reviewer.py:
import sys
import os
from google import genai
def main():
# Check that the user provided exactly one file path
if len(sys.argv) != 2:
print("Usage: python3 reviewer.py <filepath>")
sys.exit(1)
filepath = sys.argv[1]
# Verify the file actually exists before trying to read it
if not os.path.isfile(filepath):
print(f"Error: File '{filepath}' not found.")
sys.exit(1)
if __name__ == "__main__":
main()
What does this code do?
sys.argv is a list that holds whatever the user typed in the terminal. sys.argv[0] is the script name itself, and sys.argv[1] is the first argument (the file to review).
os.path.isfile() returns True only if the path points to a real file. This catches typos early with a clear error message instead of a confusing traceback.
The if __name__ == "__main__" block ensures main() only runs when you execute the script directly, not when it's imported as a module.
- Save reviewer.py.
- In your terminal (with the virtual environment still active), run this command to test the argument check:
python3 reviewer.py
- You should see Usage: python3 reviewer.py <filepath> printed in the terminal.
Seeing ModuleNotFoundError?
If you see ModuleNotFoundError: No module named 'google', your virtual environment is not active. Run source venv/bin/activate (macOS/Linux) or venv\Scripts\activate (Windows) and try again.
help me fix a ModuleNotFoundError for google-genai in my Python virtual environment
Add the file reading function
The reviewer needs to load the contents of whatever file the user points it at. A dedicated function keeps this logic clean and reusable.
- In reviewer.py, add the read_file() function between the from google import genai import line and the def main() line:
def read_file(filepath):
"""Read and return the contents of a file."""
with open(filepath, "r") as f:
return f.read()
What does this function do?
The with statement opens the file and automatically closes it when the block finishes. This prevents file handle leaks even if something goes wrong.
f.read() loads the entire file into a single string, which you'll later pass to the AI model as part of the prompt.
- Now add these lines inside main(), right after the second sys.exit(1) (the one inside the if not os.path.isfile block). Paste this code below it, still indented inside main():
print(f"Reviewing: {filepath}")
print("-" * 40)
code = read_file(filepath)
What do these lines do?
The two print lines give the user visual feedback that the script is working. The read_file() call loads the target file's contents into the code variable so you can send it to the AI in the next substep.
- Save reviewer.py.
- Test it by running:
python3 reviewer.py reviewer.py
- You should see Reviewing: reviewer.py followed by a line of dashes. The script then exits quietly because it reads the file but doesn't do anything with the contents yet.
Seeing an indentation error?
Make sure the new lines are indented with the same number of spaces as the rest of main(). Python uses 4 spaces per indent level. The print and code = read_file(filepath) lines should be at the same level as filepath = sys.argv[1].
help me fix an IndentationError in my Python script
Add the Gemini API call with system instruction
This is where the magic happens. You'll write a function that sends the source code to Gemini along with a system instruction that tells the model to act as a senior code reviewer.
System instructions shape how the model responds. By defining the output format upfront, you get structured, predictable feedback every time.
- In reviewer.py, add the review_code() function between read_file() and def main():
def review_code(code, filename):
"""Send code to Gemini for review and return the feedback."""
client = genai.Client()
system_prompt = (
"You are a senior software engineer performing a code review. "
"Analyze the provided code and give structured feedback in the following format:\n\n"
"## Bugs and Issues\n"
"List any bugs, errors, or potential runtime issues.\n\n"
"## Improvements\n"
"Suggest improvements for readability, performance, or maintainability.\n\n"
"## Style\n"
"Note any style issues or deviations from best practices.\n\n"
"## Summary\n"
"Give a brief overall assessment of the code quality.\n\n"
"If a section has no issues, write 'None found.' for that section."
)
user_message = f"Review the following code from the file '{filename}':\n\n```\n{code}\n```"
interaction = client.interactions.create(
model="gemini-3-flash-preview",
system_instruction=system_prompt,
input=user_message,
generation_config={
"temperature": 0.3
}
)
return interaction.output_text
What does this function do?
genai.Client() creates a connection to the Gemini API. It automatically reads your GEMINI_API_KEY environment variable for authentication.
The system_prompt tells the model exactly what role to play and what format to use. This is called prompt engineering. The structured sections (Bugs, Improvements, Style, Summary) ensure you get consistent output every time.
client.interactions.create() sends everything to the gemini-3-flash-preview model. A low temperature of 0.3 keeps the output focused and deterministic rather than creative.
Why a low temperature?
Temperature controls randomness in the model's output. For code review, you want precise, repeatable feedback. A value of 0.3 keeps the model focused. Higher values (closer to 1.0) produce more varied and creative responses, which is better for brainstorming but worse for technical analysis.
- Now add the final two lines to main(). Find the line code = read_file(filepath) and add these directly below it, at the same indent level:
feedback = review_code(code, filepath)
print(feedback)
What do these lines do?
These two lines complete the pipeline. review_code() sends the file contents to Gemini and returns the AI's structured review. print(feedback) displays it in the terminal for the user.
- Save reviewer.py.
- Test the complete script by running it on itself:
python3 reviewer.py reviewer.py
- You should see Reviewing: reviewer.py followed by a line of dashes, then structured AI feedback with sections like "Bugs and Issues", "Improvements", "Style", and "Summary".
Getting an API key error?
If you see an authentication error, your GEMINI_API_KEY environment variable may have expired from the terminal session. Re-export it by running:
export GEMINI_API_KEY="your-api-key-here"
Replace your-api-key-here with the key you copied from Google AI Studio. Then run the script again.
help me fix a Gemini API authentication error in my Python script
✔️ Awesome, I've got everything!
Great. Double check you've saved reviewer.py and confirm you see structured review output in your terminal.
ⓧ I'd like to double check the full code
Here is the complete reviewer.py file. Make sure yours matches exactly:
import sys
import os
from google import genai
def read_file(filepath):
"""Read and return the contents of a file."""
with open(filepath, "r") as f:
return f.read()
def review_code(code, filename):
"""Send code to Gemini for review and return the feedback."""
client = genai.Client()
system_prompt = (
"You are a senior software engineer performing a code review. "
"Analyze the provided code and give structured feedback in the following format:\n\n"
"## Bugs and Issues\n"
"List any bugs, errors, or potential runtime issues.\n\n"
"## Improvements\n"
"Suggest improvements for readability, performance, or maintainability.\n\n"
"## Style\n"
"Note any style issues or deviations from best practices.\n\n"
"## Summary\n"
"Give a brief overall assessment of the code quality.\n\n"
"If a section has no issues, write 'None found.' for that section."
)
user_message = f"Review the following code from the file '{filename}':\n\n```\n{code}\n```"
interaction = client.interactions.create(
model="gemini-3-flash-preview",
system_instruction=system_prompt,
input=user_message,
generation_config={
"temperature": 0.3
}
)
return interaction.output_text
def main():
if len(sys.argv) != 2:
print("Usage: python3 reviewer.py <filepath>")
sys.exit(1)
filepath = sys.argv[1]
if not os.path.isfile(filepath):
print(f"Error: File '{filepath}' not found.")
sys.exit(1)
print(f"Reviewing: {filepath}")
print("-" * 40)
code = read_file(filepath)
feedback = review_code(code, filepath)
print(feedback)
if __name__ == "__main__":
main()
Your code reviewer is fully built and working. Next up, you'll create test files with intentional bugs and run the reviewer on them to see how well it catches issues across different languages.
Test Your Code Reviewer
Your code reviewer is built and ready to go. Now it's time to put it to the test with real code.
The best way to verify your tool works is to feed it code with known issues. If Gemini catches bugs you intentionally planted, you know the reviewer is doing its job.
In this step, get ready to:
- Create a sample Python file loaded with intentional bugs.
- Run your reviewer and observe structured AI feedback.
- Test the reviewer on a different programming language.
Create a sample file with intentional issues
Your reviewer needs something meaty to analyze. You'll create a Python file that contains real-world code smells and bugs that a senior developer would flag during a review.
- Create a new file called sample.py in your ai-code-reviewer folder by pasting the following code:
import os
import json
import random
def process_data(data):
result = []
for i in range(len(data)):
if data[i] > 0:
result.append(data[i] * 2)
return result
def read_config(path):
f = open(path, "r")
content = f.read()
config = json.loads(content)
return config
def calculate_average(numbers):
total = 0
for n in numbers:
total = total + n
avg = total / len(numbers)
return avg
x = [1, -2, 3, -4, 5]
print(process_data(x))
print(calculate_average([]))
What bugs did we plant?
This file has several intentional issues that a good code reviewer should catch:
- os and random are imported but never used.
- process_data() uses range(len(data)) instead of iterating directly over the list.
- read_config() opens a file without a with statement, so it never closes the file handle.
- calculate_average([]) will crash with a ZeroDivisionError because it divides by len(numbers) when the list is empty.
- Save sample.py.
- Confirm the file exists by running:
ls
You should see both reviewer.py and sample.py listed in the output.
Don't see sample.py?
- Make sure you saved the file in VS Code. An unsaved file shows a dot on its tab.
- Check that your terminal is in the ai-code-reviewer folder. Run pwd to confirm.
Still stuck? Help me find where my sample.py file was saved
✔️ Awesome, I've got everything!
Great. Make sure you've saved sample.py before moving on.
ⓧ I'd like to double check the full code
import os
import json
import random
def process_data(data):
result = []
for i in range(len(data)):
if data[i] > 0:
result.append(data[i] * 2)
return result
def read_config(path):
f = open(path, "r")
content = f.read()
config = json.loads(content)
return config
def calculate_average(numbers):
total = 0
for n in numbers:
total = total + n
avg = total / len(numbers)
return avg
x = [1, -2, 3, -4, 5]
print(process_data(x))
print(calculate_average([]))
Run the reviewer on the sample file
This is the moment of truth. You'll point your reviewer at sample.py and see what Gemini finds.
- Run the reviewer on your sample file by running this command:
python3 reviewer.py sample.py
After a few seconds, you should see structured feedback printed to your terminal. The output includes sections for Bugs and Issues, Improvements, Style, and Summary.
What should I see?
The exact wording varies each time because Gemini generates fresh responses. But you should see it flag the division by zero risk, the unclosed file handle, the unused imports, and the inefficient iteration pattern.
The response follows the structured format you defined in your system_prompt with markdown headings for each section.
Seeing an error instead of feedback?
- If you see a message about your API key, check that your GEMINI_API_KEY environment variable is still set. Run echo $GEMINI_API_KEY to check. If it's empty, re-export it.
- If you see a usage message saying you need a filepath argument, make sure you included sample.py after reviewer.py in the command.
- If you see a "file not found" error, confirm both files are in the same folder by running ls.
Need more help? Help me debug why my reviewer.py is throwing an error when I run it
Test with a different language
Your reviewer isn't limited to Python. Because Gemini understands multiple programming languages, it can review code written in any language you throw at it.
- Create a new file called Sample.java in your ai-code-reviewer folder by pasting the following code:
import java.util.ArrayList;
public class Sample {
public static String formatNames(ArrayList names) {
String result = "";
for (int i = 0; i < names.size(); i++) {
result = result + names.get(i) + ", ";
}
return result;
}
public static int divide(int a, int b) {
return a / b;
}
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("Alice");
list.add("Bob");
System.out.println(formatNames(list));
System.out.println(divide(10, 0));
}
}
What issues does this Java file have?
- Raw types are used instead of generics (e.g. ArrayList instead of ArrayList<String>).
- String concatenation inside a loop is inefficient.
- divide(10, 0) will throw an ArithmeticException at runtime.
- Save Sample.java.
- Run the reviewer on the Java file by running this command:
python3 reviewer.py Sample.java
You should see structured feedback covering the Java-specific issues. Gemini identifies the raw types, the inefficient concatenation, and the division by zero risk.
Seeing the same feedback as before?
- Double check you typed Sample.java (capital S) and not sample.py. File names are case-sensitive.
- If the output mentions Python issues, you're reviewing the wrong file. Re-run with the correct filename.
Need help? Why is my reviewer showing Python feedback when I asked it to review a Java file?
Why does this work across languages?
Your reviewer doesn't parse or compile the code itself. It sends the raw text to Gemini, which understands syntax and patterns across dozens of programming languages. The AI handles the language detection automatically based on the code content and filename.
You now have a working AI-powered code review tool. You've proven it catches real bugs, flags style issues, and works across programming languages. This is the exact pattern behind every AI application: send structured input, get structured output.
Secret mission
Multi-File Review with Markdown Report
Your reviewer works great on one file at a time. But real projects have dozens of files. Can you extend your tool to review multiple files in a single command and save the results to a professional markdown report?
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally and uses the Gemini API free tier, so there are no ongoing costs. Decide whether to keep your resources running or delete them entirely.
Resources you used:
- The ai-code-reviewer project folder (includes virtual environment, scripts, and sample files).
- A Gemini API key (free tier, no ongoing cost).
Keep everything running
No action needed. Choose this if you're still actively building or want to reference your code later.
- Your API key stays on the free tier indefinitely. There are no charges for keeping it active.
- Your project folder remains on your Desktop. The virtual environment only takes up space on disk.
Pause - I'll come back to this later
Free up terminal resources while keeping your files intact.
- Deactivate your virtual environment by running:
- Close VS Code and any open terminal windows.
deactivate
Your project folder and API key remain ready for next time. To resume, reactivate the virtual environment with source venv/bin/activate from inside the project folder.
Delete - I don't want to use this again
Remove all project resources and revoke your API key.
- Delete the project folder by running this command (macOS/Linux):
rm -rf ~/Desktop/ai-code-reviewer
- On Windows, run this instead:
Remove-Item -Recurse -Force ~\Desktop\ai-code-reviewer
- Revoke your Gemini API key by visiting the API Keys page in Google AI Studio:
https://aistudio.google.com/apikey
- Find the key you created for this project in the list.
- Click the trash icon or delete option next to the key to remove it.
- The GEMINI_API_KEY environment variable was session-only (set with export). It disappears automatically when you close your terminal.
Nice Work!
Nice Work!
You just built a fully functional AI-powered code review tool from scratch using Python and the Google Gemini API.
You've learned how to:
- Set up a Python development environment from scratch with VS Code, virtual environments, and pip.
- Built a working CLI tool that calls the Gemini API with a system instruction and processes structured output.
- Used the core LLM API pattern (system instruction + user input = structured response) that powers every AI application.
- Secret Mission: Extended the tool to review multiple files at once and generate a professional markdown report.
Ready to quiz yourself?