Build an AI Runbook Generator with Claude API and Git History
Auto-generate incident runbooks from your git history, monitoring alerts, and past incidents using Claude API. Runbooks stay up to date automatically as your code changes — no manual maintenance.
Runbooks go stale within weeks of being written. This tool uses Claude API to generate runbooks from your actual git history, Kubernetes configs, and alert definitions — so they reflect what the system actually does.
Setup
pip install anthropic gitpython pyyamlGenerate Runbook from Service Context
import anthropic
import subprocess
import yaml
import json
from pathlib import Path
client = anthropic.Anthropic()
def get_git_context(repo_path: str, service_name: str) -> dict:
"""Extract relevant context from git history."""
context = {}
# Recent commits for this service
result = subprocess.run(
["git", "log", "--oneline", "-20", "--", f"*{service_name}*"],
capture_output=True, text=True, cwd=repo_path
)
context["recent_commits"] = result.stdout
# Check for incident-related commits
result = subprocess.run(
["git", "log", "--oneline", "-50", "--grep=fix", "--grep=hotfix", "--grep=incident", "--all-match"],
capture_output=True, text=True, cwd=repo_path
)
context["incident_commits"] = result.stdout
return context
def get_kubernetes_context(namespace: str, deployment_name: str) -> dict:
"""Get deployment configuration."""
context = {}
result = subprocess.run(
["kubectl", "get", "deployment", deployment_name, "-n", namespace, "-o", "yaml"],
capture_output=True, text=True
)
if result.returncode == 0:
dep = yaml.safe_load(result.stdout)
# Extract key info only
spec = dep.get("spec", {})
containers = spec.get("template", {}).get("spec", {}).get("containers", [])
context["replicas"] = spec.get("replicas", 1)
context["containers"] = [
{
"name": c["name"],
"image": c["image"],
"ports": c.get("ports", []),
"env_count": len(c.get("env", [])),
"readiness_probe": bool(c.get("readinessProbe")),
"resources": c.get("resources", {})
}
for c in containers
]
# Get HPA if exists
result = subprocess.run(
["kubectl", "get", "hpa", "-n", namespace, "-o", "json"],
capture_output=True, text=True
)
if result.returncode == 0:
hpa_data = json.loads(result.stdout)
context["hpa"] = [
{
"name": item["metadata"]["name"],
"min": item["spec"].get("minReplicas"),
"max": item["spec"]["maxReplicas"],
}
for item in hpa_data.get("items", [])
if item["spec"]["scaleTargetRef"]["name"] == deployment_name
]
return context
def generate_runbook(
service_name: str,
namespace: str = "production",
repo_path: str = ".",
alert_description: str = None
) -> str:
"""Generate a complete runbook for a service."""
git_context = get_git_context(repo_path, service_name)
k8s_context = get_kubernetes_context(namespace, service_name)
prompt = f"""You are an experienced SRE writing an operational runbook.
## Service Information
- Service: {service_name}
- Namespace: {namespace}
- Replicas: {k8s_context.get("replicas", "unknown")}
- Auto-scaling: {json.dumps(k8s_context.get("hpa", []))}
- Containers: {json.dumps(k8s_context.get("containers", []), indent=2)}
## Recent Git History
{git_context.get("recent_commits", "No recent commits found")}
## Past Incident Commits
{git_context.get("incident_commits", "No incident commits found")}
{f"## Alert Being Investigated\n{alert_description}" if alert_description else ""}
Generate a complete operational runbook in Markdown for this service. Include:
1. **Service Overview** — what it does, dependencies, SLO
2. **Health Checks** — kubectl commands to verify service health
3. **Common Incidents** — based on git history, list likely failure modes
4. **Diagnosis Steps** — step-by-step commands to diagnose issues
5. **Escalation Path** — when to escalate and to whom
6. **Rollback Procedure** — exact commands to roll back
7. **Useful Commands** — kubectl, curl, log commands for this specific service
Make it specific and actionable. Use real kubectl commands with the actual namespace and service name."""
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=3000,
messages=[{"role": "user", "content": prompt}]
)
return response.content[0].text
def save_runbook(service_name: str, runbook_content: str, output_dir: str = "runbooks/"):
"""Save runbook as markdown file."""
Path(output_dir).mkdir(exist_ok=True)
output_path = Path(output_dir) / f"{service_name}-runbook.md"
output_path.write_text(runbook_content)
print(f"Runbook saved: {output_path}")
return str(output_path)
if __name__ == "__main__":
import sys
service = sys.argv[1] if len(sys.argv) > 1 else "payment-service"
namespace = sys.argv[2] if len(sys.argv) > 2 else "production"
alert = sys.argv[3] if len(sys.argv) > 3 else None
print(f"Generating runbook for {service} in {namespace}...")
runbook = generate_runbook(service, namespace, alert_description=alert)
path = save_runbook(service, runbook)
print(f"\nRunbook generated: {path}")
print("\nPreview:")
print(runbook[:500] + "...")Example Output
# payment-service Runbook
## Service Overview
The payment-service handles all payment processing for the platform.
It calls Stripe API, writes to PostgreSQL, and publishes events to SQS.
SLO: 99.9% availability, p99 latency < 500ms.
## Health Checks
kubectl get pods -n production -l app=payment-service
kubectl top pods -n production -l app=payment-service
kubectl logs -n production -l app=payment-service --tail=100 | grep -i error
## Common Incidents (from git history)
1. Stripe API timeout (6 past incidents) — payment-service/stripe_client.py
2. Database connection pool exhaustion — increases under load spikes
3. SQS dead letter queue buildup — check when deployments fail mid-publish
## Diagnosis Steps
...Automate Weekly Runbook Updates
# .github/workflows/update-runbooks.yml
name: Update Service Runbooks
on:
schedule:
- cron: '0 6 * * 1' # Monday 6 AM
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate updated runbooks
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
pip install anthropic gitpython pyyaml
for service in payment-service api-gateway user-service; do
python generate_runbook.py $service production
done
- name: Commit updated runbooks
run: |
git config user.name "github-actions"
git config user.email "github-actions@github.com"
git add runbooks/
git diff --staged --quiet || git commit -m "Auto-update runbooks [skip ci]"
git pushRunbooks that update themselves from real system context stay accurate — the fundamental problem with manually maintained runbooks.
More AI SRE tools? Read our Build AI on-call assistant with PagerDuty and Claude and LLM-powered incident response.
Today I Fixed
Short real fixes from production — posted daily
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.
Related Articles
Build an AI ChatOps Incident Bot for Slack with Claude API
Build a Slack bot that turns '/incident api is down' into a full incident channel with a Claude-generated initial assessment, relevant runbook links, and the right people paged automatically.
Build an AI Incident Timeline Reconstructor with Claude API
Writing an incident timeline after the fact means manually cross-referencing Slack messages, deploy logs, alert timestamps, and PagerDuty events. Build a tool that pulls all of it together and generates an accurate, chronological timeline with Claude API.
Build an AI Load Test Scenario Generator with Claude API
Writing realistic k6 or Locust load test scenarios means understanding actual traffic patterns, not just hammering one endpoint. Build a tool that reads your API spec and real traffic logs, then generates realistic load test scripts with Claude API.