
TL;DR#
I used to have pull requests with dozens (and sometimes hundreds) of commits, and most commit messages were complete garbage. Cleanup., More tests., fix., some initial notes – you got the idea.
The fix was not discipline. Discipline does not scale very well when you commit often, work with AI agents, constantly jump between projects and branches, and still want to keep flow. The fix was two tiny prompt files:
commit.mdreads the staged diff and creates a short descriptive commit message.create-pull-request.mdreads the commit log, generates a PR title and description, pushes the branch, and runsgh pr create.- Good commit messages become good PR descriptions. Good PR descriptions give your teammates better review context. And now your AI agent also has better history to inspect later.
This is not a complex system. That’s exactly why I like it.
Video Walkthrough#
If you prefer a visual walkthrough, I made a video for this post where I show how these two prompts fit into my AI-assisted Git workflow.
The Problem Is Not That You Cannot Write Good Commits#
You can write good commit messages. I can too.
The problem is that we usually do not. Not every time. Not when the change is small. Not when it is late. Not when you’re in the middle of agentic engineering flow and you just want to checkpoint before the next step. And especially if you’re manually coding some complex edge case (yes I still do it sometimes), context switch is not fun.
I had a real pull request with 209 commits. Mine. A lot of the messages were things like:
Cleanup.
More tests.
Some initial notes.
More readme.
fix.
more changes.Now sure, you will squash before merging. But what does the squashed commit say? Very often it says some slightly better version of nothing. And if GitHub is using default merge commit behavior, you may not even get the PR title and description in the final commit unless you configure it, or manually write it again!
And you may say, well “Who reads commit messages?” and well, yeah, usually nobody. Until you and your AI buddy are hunting a regression across 200 commits for the past three months, with production being on fire. Then everyone suddenly cares very much about what changed and why.
Commit messages are not ceremony. They are your future search index and journal of your work.
So let’s jump right in and show you how to fix this, just two prompts and that’s it!
Prompt One: commit.md#
The first file is the commit prompt. It can live anywhere your agent can reference it. I usually keep this kind of stuff under .agents/commands/ or similar and then symlink or reference it as harness specific command. I personally prefer to design my prompts/skills/commands in a more or less harness agnostic way, but if you use just a single harness/vendor, it maybe best to just stick to your harness way of defining commands.
And the file is just those few lines:
# Follow this instruction to commit changes.
* All commands should be run from a repo root.
* Commit all updated files if not otherwise specified. Use `git add .`.
* Use `git diff --staged | head -n 1000` to understand the change.
* Create a short descriptive commit message based on the diff.
* Use chat history only as extra context, not as the source of truth.
Do **NOT** do any other verification or actions unrelated to this instruction.If you don’t force the model to read the diff, it will happily use chat history or just list changed files and come-up with slightly longer but equally useless message. The staged diff is the thing you are actually committing.
And it doesn’t matter if you run this command or you agent does it while running some big orchestration loop, the result is the same: you get a commit message that describes the change.
The Guardrail Line#
This line matters more than it looks:
Do **NOT** do any other verification or actions unrelated to this instruction.Without it, helpful agents may sometimes try to be too helpful. They may run lint and tests. They may format files. Maybe they start fixing something if they spot a “bug” in that diff… Suddenly your five-second checkpoint becomes five-minute battle field of your agent with the codebase and you’re lucky if you notice and stop this madness.
The prompt has one job: commit current changes with a useful message and this “magic” line is a sort of a guardrail to make sure it doesn’t do anything else.
Prompt Two: create-pull-request.md#
The second prompt is the companion file. It creates the PR from the commit history. It can work on its own, but they work best together. As mentioned - good commits make good PR descriptions.
The prompt is a bit longer, but conceptually it is doing the following:
git fetch origin- well you know what that isgit log origin/main...HEAD --oneline | cat- list of nicely formatted commit messages (produced bycommit.mdideally)- Synthesize title and description based on the commit log
git pushandgh pr create
Nothing fancy, just a few commands and a bit of text processing. So here is the full prompt:
# Instruction to create pull request
This is an instruction to follow when user is referencing it. Only use this instruction when explicitly requested by the user.
1. Look on a commit history between a base (if not mentioned otherwise, use **main**). You will need to run command like below
```bash
# Make sure remote is up to date
git fetch origin
# to get current branch, you will use it in step 5
git branch
# git log
git log origin/<base branch>...HEAD --oneline | cat
```
2. Review commit history (git log output above) and come up with a sensible PR title and description.
3. The description should summarize meaningful changes and follow format similar to below:
```md
# Focus of the changes
<Short summary of the changes (1-2 sentences), what they are about and why they are needed.>
# High level summary of the changes
* Short change description 1
* Short change description 2
* ...
```
Note: Use your best judgement and feel free to adjust the format if changes are more complex and require more detailed description. The main point is to make it easy for reviewers (usually humans, and humans do not like to read poems) to understand what changes are about and why they are needed.
4. Prepare PR title and description in the following format:
```md
**PR title**:
<PR title>
---
**PR description**:
<PR description>
```
5. Push pending changes and create a PR with a command below:
```bash
git push origin <current branch> --set-upstream
gh pr create --title "<PR title>" --base <base branch> --head <current branch> --body "$(cat <<EOF
# Focus of the changes
<Short summary of the changes (1-2 sentences), what they are about and why they are needed.>
# High level summary of the changes
* Short change description 1
* Short change description 2
* ...
EOF
)"
```
Note: Using cat and EOF allows you to create a multi-line PR description without worrying about escaping special characters. Make sure to use actual PR title and description and other parameters as needed.
6. Show the PR to the user as a URL so user can click it, as well as full URL for copying.And you can easily tune what you want to see in the PR title and description, it’s just a text prompt, so adjust it to your needs.
How do I run this?#
For the commit.md one, I usually do it like this:
- Running it manually when I want to check-point my work (e.g
/commitor justfollow @commit.md). And this mode is probably not as frequent these days. - Have my agent run it while in progress of some long running orchestration loop. In this case it’s usually part of a verification step that is executed in a dedicated sub-agent.
The create-pull-request.md is basically same story, running it either myself or my agent runs it when it’s time to submit the PR.
Before And After#
Typical commit messages produced the “old way”:
- cleanup
- fix
- more changes
- update tests
- final tweaksAnd this is what you can expect from the “new way”:
- Add AccountsStore load/validate/query and tests
- Add cmd/bbmd Cobra scaffold and DI smoke tests
- Implement bbmd auth sub-commands
- Implement bbmd pr sub-commands
- bbmd: unify auth/PR execution via exec helpers and testsAnd of course PR title and description are way better. Here is one of the PRs I created with this workflow: https://github.com/gemyago/atlacp/pull/38
If something goes wrong#
If you notice some misbehavior with those prompts, I have a very handy technique that helps to diagnose and fix such misbehavior - Agent Diagnostics Mode. You can use this technique to fix issues with your prompts, not just those commit/pull request ones, but in general - any model misbehavior. This was a handy tool for me and still is.
Model Choice: Please Do Not Use Your Most Expensive Model#
Using a premium reasoning model for commit messages is probably too much. Sure if it’s one-off and you just don’t want to leave the session - fine. But doing it all the time will burn your budget quicker, especially if your agent is orchestrating some big work and doing checkpoints often.
Use whatever fast and cheap model you have access to, experiment with it to make sure it is handling the task well, maybe even tune the prompt if it’s confusing to the model. Local models may also be interesting here, especially for housekeeping prompts like this one.
Save your budget on complex stuff, commit messages do not need that.
Is this lazy?#
Maybe. But it is the good kind of lazy.
The output is better, the friction is lower, and the history is more useful. I will take that trade-off.

