Automated code reviews can run in isolated environments without relying on resources running 24/7. This article explains how to use disposable Firecracker microVMs on AWS to execute an LLM-based code review. It describes a small reference implementation consisting of shell scripts, a host-side LLM proxy, and a GitHub Actions workflow, with each pull request getting its own short-lived virtual machine.
Key Takeaways
- AWS Lambda MicroVMs use Firecracker virtualization to provide isolated execution environments. Pre-initialized snapshots allow new microVMs to start without repeating the application setup.
- GitHub Actions can trigger an automated review when a pull request is opened or new commits are pushed to it. A Python agent retrieves the diff, sends it to Claude, and posts the resulting feedback to GitHub.
- Each review runs in a separate, short-lived microVM that terminates after completing its task. This limits the lifetime of the execution environment and helps control compute costs.
What are AWS Lambda MicroVMs?
AWS Lambda MicroVMs are a serverless compute primitive designed to safely execute untrusted code generated by users or AI agents in fully isolated environments. They are built on Firecracker virtualization technology, so they combine the strong security boundary of a virtual machine with the scalability of serverless computing.
Why do we need this?
Imagine you need to build something with the help of agentic AI, but you do not want to risk damaging your production environment.
A microVM is like a tiny, disposable, secure workshop. You run a task inside it in isolation. If you need to pause, you can suspend the microVM, preserve its state, and resume it when you are ready. When it is suspended, you do not pay for compute resources, although snapshot storage charges still apply.
For engineers, this means every user or task can get its own isolated, cheap, and instant workspace without the complex setup and cost of running a traditional server.
Why Containers Were Not the Boundary We Wanted
The usual answer is “Put it in a container.” A container is a set of namespaces and groups on top of the host kernel, so a kernel bug is a path out. For a service that runs code written by AI or reads text from strangers while holding keys, that is a thin wall.
A microVM changes the trade-off. Each job gets its own guest kernel, isolated by hardware virtualization (KVM). Firecracker removes almost everything a normal VM carries around (no BIOS, almost no device emulation, just a handful of virtual devices), which is why it boots quickly and has a small attack surface. AWS runs Lambda and Fargate on it.
Important: This article contains only basic examples, and some details have been intentionally omitted, such as prompts and secrets injection. The code should not be considered ready for production use. The article is intended only to give an overview of what microVMs can do.
Flow Overview
- A new pull request is opened against the main/master branch.
- GitHub Action: Detects a new PR and sends a lightweight webhook to AWS API Gateway.
- AWS Launcher: A small Lambda function verifies the webhook and calls run-microvm to boot a dedicated microVM from a pre-initialized snapshot.
- The Sandbox: Inside the microVM, a Python script pulls the PR diff, sends it to Claude for review, and posts the feedback to GitHub.
- Self-Termination: The microVM calls TerminateMicrovm immediately after finishing to reduce costs.
Step 1: Create the MicroVM Image
To get started, navigate to the AWS Lambda console, where you will find Lambda MicroVMs in the left-hand navigation menu.
First, we describe the microVM using a Dockerfile:
FROM public.ecr.aws/lambda/microvms:al2023-minimal
# Install Python and Git
RUN dnf install -y python3 python3-pip git && dnf clean all
WORKDIR /app
# Install dependencies for the agent
RUN pip3 install --no-cache-dir flask gunicorn requests anthropic boto3
COPY agent.py /app/agent.py
EXPOSE 8080
# Start the agent's web server. AWS calls it when the microVM resumes
CMD ["gunicorn", "--bind", "127.0.0.1:8080", "--workers", "1", "agent:app"] Step 2: Write the Review Agent
The agent is a tiny Flask app. AWS sends a request to its run hook when the microVM resumes. The agent downloads the PR diff, asks Claude to review it, posts the answer as a PR comment, and then terminates its own microVM.
Review Agent sample code:
import json
import os
import boto3
import requests
from anthropic import Anthropic
from flask import Flask, request
app = Flask(__name__)
PROMPT = "Here you will write your prompt"
def review_pull_request(pr_url, comments_url):
github_headers = {
"Authorization": f"Bearer {os.environ['GITHUB_TOKEN']}",
"Accept": "application/vnd.github.v3.diff",
}
diff = requests.get(pr_url, headers=github_headers, timeout=30).text
claude = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
message = claude.messages.create(
model="some actual claude model",
max_tokens=4096,
messages=[{"role": "user", "content": f"{PROMPT}\n\n{diff}"}],
)
review = message.content[0].text
github_headers["Accept"] = "application/vnd.github+json"
requests.post(comments_url, json={"body": review}, headers=github_headers, timeout=30)
@app.post("/aws/lambda-microvms/runtime/v1/run")
def run_hook():
"""Called by AWS when the microVM resumes."""
envelope = request.get_json()
payload = json.loads(envelope["runHookPayload"])
try:
review_pull_request(payload["pr_url"], payload["comments_url"])
finally:
# Terminate the microVM so nothing is left running
boto3.client("lambda-microvms").terminate_microvm(microvmId=envelope["microvmId"])
return "OK"
if __name__ == "__main__":
app.run(host="127.0.0.1", port=8080)Step 3: Build the Image with the AWS CLI
Zip the files
zip -r microvm-app.zip Dockerfile agent.py Upload the ZIP file to S3
aws s3 cp microvm-app.zip
s3://my-devops-artifacts-bucket/microvm-app.zipCreate the microVM image
aws lambda-microvms create-microvm-image \
--code-artifact uri=<path/to/s3/artifact.zip> --name <VM_image_name> \
--base-image-arn arn:aws:lambda:us-east-1:aws:microvm-image:al2023-1 \
--build-role-arn <IAM role ARN>After you run the command, Lambda retrieves the ZIP file, builds the Dockerfile, initializes the application, and takes a Firecracker snapshot of the running disk and memory state.
Behind the scenes, AWS does the following:
1. Downloads your ZIP file from S3.
2. Builds the Dockerfile and installs all the dependencies.
3. Starts Gunicorn and waits until the server is ready to accept requests.
4. Takes a snapshot of this running state and saves it.
Each new microVM then starts from that snapshot, which is why it becomes available almost instantly instead of booting and installing everything from scratch.
Step 4: Prepare the GitHub Workflow
Now we prepare the workflow for the Git repository. It runs on every new or updated pull request and notifies the AWS launcher:
This example assumes that the API Gateway key is stored in the repository’s secrets.
name: Trigger MicroVM AI Code Review
on:
pull_request:
types: [opened, synchronize]
jobs:
dispatch-review:
runs-on: ubuntu-latest
steps:
- name: Dispatch Event to AWS Launcher
run: |
curl -X POST https://api.your-aws-domain.com/launch-review \
-H "Content-Type: application/json" \
-H "X-API-Key: ${{ secrets.AWS_API_GATEWAY_KEY }}" \
-d '{
"pr_url": "${{ github.event.pull_request.url }}",
"comments_url": "${{ github.event.pull_request.comments_url }}"
}'Step 5: The Launcher Lambda
In our example, the workflow does not talk to the microVM directly. It calls API Gateway, which invokes a small “launcher” Lambda function. The launcher checks the request and starts a new microVM from the image, passing the PR links as the run hook payload.
The launcher then immediately returns HTTP 202 response, allowing the GitHub job to be completed in a few seconds. The review itself runs asynchronously in the microVM and appears as a comment on the pull request. The launcher must pass an –execution-role-arn when calling run-microvm. This role is what grants the microVM permission to call boto3.
The method for injecting secrets is left to the user’s discretion.
What happens on every pull request:
1. The developer pushes a commit, and GitHub Actions calls API Gateway.
2. The launcher Lambda resumes a microVM from the saved snapshot.
3. AWS calls the run hook with the PR links.
4. The agent downloads the diff, asks Claude for a review, and posts the comment.
5. The agent terminates the microVM, and nothing is left running or billed.
Conclusion
This example illustrates the basic pattern and can be expanded and improved in several ways, adding multiple agents, enabling notifications, or using a microVM for AI-driven and end-to-end testing.
With a Dockerfile, around forty lines of Python, and a short workflow, every pull request gets its own AI code review inside a disposable, isolated virtual machine. If a malicious diff confuses the model, the damage stays inside a sandbox that is destroyed minutes later. Snapshots enable fast startups, and self-termination keeps cost close to zero when nobody is opening pull requests.
TL;DR
The article provides sample code for the main components, including the Dockerfile, review agent, and GitHub Actions workflow. Some implementation details, such as the launcher Lambda code and secrets management, are left out.
