We're building a CLI tool that reads staged git diffs and writes a commit message, PR title, and description. It saves time and keeps history consistent. Because Oxlo.ai uses flat per-request pricing, the diff size does not change what you pay, so we can pass the full patch on every call. See oxlo.ai/pricing for details.
What you'll need
- Python 3.10 or newer
- The OpenAI SDK:
pip install openai - An Oxlo.ai API key from https://portal.oxlo.ai
Step 1: Verify connectivity
First, I make sure the client can reach Oxlo.ai and that my key is active. I run a quick smoke test against Llama 3.3 70B.
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "user", "content": "Say 'Oxlo.ai is up'"},
],
)
print(response.choices[0].message.content)
Step 2: Capture the diff
I use the subprocess module to grab staged changes. I strip excess metadata and truncate only if we approach the model context window, not because of cost.
import subprocess
def get_staged_diff(max_chars=8000):
result = subprocess.run(
["git", "diff", "--staged"],
capture_output=True, text=True
)
diff = result.stdout.strip()
if len(diff) > max_chars:
diff = diff[:max_chars] + "\n... [truncated]"
return diff
if __name__ == "__main__":
diff = get_staged_diff()
print(f"Captured diff length: {len(diff)} characters")
Step 3: The system prompt
This prompt defines the tone and schema. I keep it strict so the model returns exactly three labeled sections.
SYSTEM_PROMPT = """You are a technical editor that turns git diffs into structured prose.
Read the diff and produce exactly these sections:
Commit Message: a single-line imperative sentence (max 72 chars)
PR Title: a concise title summarizing the change
PR Description: 2-4 bullet points describing what changed and why
Do not include markdown code fences. Use plain text only."""
Step 4: Generate the draft
Now I call Oxlo.ai with the diff as the user message. I use llama-3.3-70b because it follows formatting instructions reliably. If your team writes in multiple languages, qwen-3-32b is a solid alternative.
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
SYSTEM_PROMPT = """You are a technical editor that turns git diffs into structured prose.
Read the diff and produce exactly these sections:
Commit Message: a single-line imperative sentence (max 72 chars)
PR Title: a concise title summarizing the change
PR Description: 2-4 bullet points describing what changed and why
Do not include markdown code fences. Use plain text only."""
def generate_notes(diff_text: str) -> str:
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": diff_text},
],
temperature=0.3,
)
return response.choices[0].message.content
if __name__ == "__main__":
diff = get_staged_diff()
output = generate_notes(diff)
print(output)
Step 5: Parse and emit structured output
Parsing free text is fragile, so I switch to JSON mode. I update the prompt to request a JSON object and set response_format to json_object. This gives us machine-readable fields we can echo or pipe into other tools.
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
SYSTEM_PROMPT = """You are a technical editor that turns git diffs into structured prose.
Read the diff and return a JSON object with exactly these keys:
- commit_message: string, imperative, max 72 chars
- pr_title: string, concise summary
- pr_description: string, 2-4 bullet points
Rules: output valid JSON only. No markdown fences."""
def generate_notes(diff_text: str) -> dict:
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": diff_text},
],
response_format={"type": "json_object"},
temperature=0.3,
)
raw = response.choices[0].message.content
return json.loads(raw)
if __name__ == "__main__":
diff = get_staged_diff()
result = generate_notes(diff)
print(json.dumps(result, indent=2))
Run it
Stage some changes and execute the script.
$ git add src/api.py tests/test_api.py
$ python draft_generator.py
Example output:
{
"commit_message": "Add input validation to API endpoints",
"pr_title": "Validate incoming API payloads before processing",
"pr_description": "- Adds Pydantic models for request schema validation\n- Returns 422 errors with detailed field feedback\n- Covers edge cases for null timestamps and empty arrays"
}
Wrap-up
You now have a working generator that turns diffs into structured narrative. Two concrete next steps: wire this into a git prepare-commit-msg hook so it runs automatically, or extend the prompt to reference your CONTRIBUTING.md style guide for project-specific voice.
Top comments (0)