Commit writer · auto-split commits from morning changes
Feed uncommitted git diff to Qwen3.8-flash; it auto-splits into multiple commits, writes Conventional Commits titles and bodies, and flags breaking changes.
Hand uncommitted multi-file diff to the model; let it decide how many commits to split, which files go where, and whether any change breaks callers.
Note
Disclaimer: All content on this page is AI-generated, for reference only, and does not constitute any performance guarantee. Actual results and Credits consumption are subject to the console "Usage Details".This walkthrough uses a multi-file diff mixing three unrelated changes (bug fix + new feature + cleanup): hand the diff to qwen3.8-flash, and it decides split granularity, writes Conventional Commits subject + body for each, flags breaking changes, and gives a PR title and pre-commit reminders. The diff includes 5 traps to test whether it reads the diff or guesses from function names.
Call chain: qwen3.8-flash (uncommitted diff in one input → commit list + PR title + pre-commit reminders). Thinking mode off, short input, shorter output.
Steps: hand the diff to the model for splitting
Send the git diff content along with the prompt below to qwen3.8-flash. Writing commits is a several-times-a-day action; thinking off is recommended. The diff below is excerpted for readability:
You are a Git commit assistant. Below are uncommitted changes accumulated over a morning in my working tree.
Decide how many commits these changes should be split into, and write commit messages for each.
Return only a JSON object, no other text, with this fixed structure:
{
"commits": [
{
"subject": "Conventional Commits title, format type(scope): description, max 50 chars",
"body": "Explain why and impact, two or three sentences; if nothing to say, empty string",
"files": ["file paths belonging to this commit"],
"breaking": true or false
}
],
"pr_title": "If these changes go in one PR, what's the PR title",
"notes": ["things worth reminding me before committing; empty array if none"]
}
Requirements:
- Unrelated changes must be split; don't lump into one. Related changes should be grouped; don't over-split.
- subject should state what behavior changed; don't write "update code" or "modify files"—zero information.
- body should explain why and who's affected; don't restate the diff line by line.
- If a change breaks callers (function signature changed, return value changed, incompatible behavior),
set breaking to true and state in body how callers should adapt.
- Judge based on actual diff content, not function or file names.
Changes to commit:
diff --git a/src/service/user_service.py b/src/service/user_service.py
@@ -45,7 +45,10 @@ class UserService:
def get_profile(self, uid):
raw = self.cache.get(uid)
- return json.loads(raw)
+ if raw is None:
+ return None
+ return json.loads(raw)
@@ -78,9 +81,9 @@ class UserService:
- def validateCache(self, uid):
- ts = self.cache.ttl(uid)
- return ts > 0
+ def validateCache(self, uid):
+ ts = self.cache.ttl(uid)
+ # originally only checked if ttl is positive; cross-day keys would be judged valid
+ return ts > 0 and (time.time() - self.cache.mtime(uid)) < 86400
diff --git a/src/api/export.py b/src/api/export.py
@@ -0,0 +1,24 @@
+import csv
+from io import StringIO
+
+@app.route("/api/users/export")
+def export_users():
+ """Export filtered user list as CSV"""
+ rows = UserService().query(request.args)
+ buf = StringIO()
+ w = csv.writer(buf)
+ w.writerow(["uid", "name", "created_at", "status"])
+ for r in rows:
+ w.writerow([r.uid, r.name, r.created_at, r.status])
+ # TODO: add tests later
+ return Response(buf.getvalue(), mimetype="text/csv")
diff --git a/src/service/exporter.py b/src/service/exporter.py
@@ -12,8 +12,8 @@ class UserExporter:
- def export(self, rows, encoding, with_header):
- out = self._render(rows, encoding, with_header)
+ def export(self, rows, with_header):
+ out = self._render(rows, "utf-8", with_header)
return out
diff --git a/src/api/handler.py b/src/api/handler.py
@@ -33,7 +33,6 @@ def handle_request(req):
ctx = build_context(req)
- print("DEBUG ctx:", ctx)
return dispatch(ctx)
diff --git a/README.md b/README.md
@@ -8,7 +8,7 @@
-This project requires Python 3.9+. Please creat a virtual environment before instaling.
+This project requires Python 3.9+. Please create a virtual environment before installing.
diff --git a/requirements.txt b/requirements.txt
@@ -3,4 +3,4 @@ flask==3.0.0
-redis==4.5.1
+redis==5.0.1
requests==2.31.0
Key parameters:
{
"model": "qwen3.8-flash",
"messages": [{"role": "user", "content": "…git diff body…"}],
"enable_thinking": false
}
Under OpenAI-compatible mode, enable_thinking goes at the top level of the request body.
View measured output · 5 commits + PR title + pre-commit reminders (excerpt)
{
"commits": [
{
"subject": "fix(service): handle cache miss and improve TTL validation",
"body": "Fix get_profile crash when parsing None on cache miss; returns None. Fix validateCache logic: add mtime check so cross-day keys aren't judged valid.",
"files": [
"src/service/user_service.py"
],
"breaking": false
},
{
"subject": "feat(api): add user CSV export endpoint",
"body": "Add /api/users/export endpoint to export filtered user data as CSV. This feature currently lacks test coverage; needs follow-up.",
"files": [
"src/api/export.py"
],
"breaking": false
},
{
"subject": "refactor(exporter): remove encoding param from export method",
"body": "Simplify UserExporter.export signature; internally fix UTF-8 encoding. Callers that explicitly pass an encoding param need to remove it to adapt.",
"files": [
"src/service/exporter.py"
],
"breaking": true
},
{
"subject": "chore: remove debug print and fix README typo",
"body": "Clean up debug output in handler.py to avoid production log pollution. Fix 'installing' typo in README.md.",
"files": [
"src/api/handler.py",
"README.md"
],
"breaking": false
},
{
"subject": "build: upgrade redis client to v5.0.1",
"body": "Upgrade redis from 4.5.1 to 5.0.1. Verify existing Redis connection config is compatible with v5 client, especially timeout and retry settings.",
"files": [
"requirements.txt"
],
"breaking": false
}
],
"pr_title": "Fix cache handling, add CSV export, refactor exporter API, and update deps",
"notes": [
"UserExporter.export signature change is a breaking change; before merging, search globally and update all call sites to remove the encoding param.",
"Redis major-version upgrade (4.x -> 5.x) may introduce behavioral differences; recommend validating connection stability and command execution in staging.",
"The new CSV export endpoint has no unit tests yet; recommend adding them soon to ensure data safety and format correctness."
]
}
Notes
- Consumption: This playbook uses text generation (qwen3.8-flash, thinking off). Both input and output are short—the lowest cost and fastest of the 7 playbooks in this batch.
- Measured result: 6 files of changes split into 5 commits; file attribution all correct. The 5 preset traps all handled correctly—three typical ones:
UserExporter.export()parameter removal flagged as breaking with caller adaptation instructions; function namedvalidateCachebut actually changes expiry-time calculation—it read the diff, not the name;# TODO: add tests laterin the diff wasn't copied into a commit message, but promoted to a pre-commit reminder. - Note: The prompt asks for subject ≤ 50 chars; 2 of 5 exceeded. Hard constraints like char count should be re-checked in a commit hook.
- Note: The diff shown here is excerpted; when running it yourself, input length will differ from the tested round, and split results may vary.