We standardized our commits with a tiny Rust CLI (and it changed our code reviews)
TL;DR: At Bookcicle we wanted every commit and PR to read like a pro wrote it—concise, conventional, and consistent. We built a small Rust binary, commitmsg, that shells out to git, composes a structured prompt, and calls OpenAI to generate either a Conventional Commit message or a crisp PR description from the actual diff. It’s fast, repeatable, and—most importantly—keeps human intent front and center.
Repo: bookcicle/commitmsg (public on GitHub)
Why we did this
If you’ve ever reviewed code after a long day, you know the pain:
We wanted a lightweight way to nudge everyone (including me!) toward the same high bar, without adding friction or inventing a new process. The constraints were simple:
What we built
commitmsg is a single binary that does two jobs:
Under the hood it:
Safety & DX defaults you’ll care about:
Quickstart
Requires OPENAI_API_KEY and git on your PATH - More installation instructions, and use details in the project Readme.md
Dry Run -- Our Favorite Use
commitmsg --dry-run
Full Example:
$commitmsg --dry-run
feat(processor): persist stage on phase gate open and probe fan-out fix
- track open_now to respect successful probe and enable fan-out
- update stage in checkpoint store when gate opens for watchdog/UI
- warn on stage update failure without aborting workflow
- refactor test to seed starter stage and assert stage persistence
- add helper to seed task with sections for reuse
- expand test name to cover stage and probe behavior
saved → /tmp/commitmsg.txt
--- end of commit message ---
| Running git commit --dry-run… → git commit --dry-run -F /tmp/commitmsg.txt
/ Running git commit --dry-run… On branch ab/persist-stage-on-phase-gate-open
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: src/processor/core.rs
modified: tests/expanded_ghostwriting_workflow_integration.rs
Approve commit? [y/N] y
Generate a Conventional Commit from staged changes:
commitmsg --strict
Use the last commit (HEAD) instead of staged:
commitmsg --head
Generate a PR description (auto-detects base like origin/main → main → master):
commitmsg --desc
Be explicit about the range/base:
commitmsg --desc --range main...HEAD
# or
commitmsg --desc --base origin/main
Turn on streaming + bump reasoning effort/verbosity (when diffs are gnarly):
commitmsg --stream --effort high --verbosity high
Examples Real, Generated Commits:
feat(healers): add watchdog throttle/marking and ghostwriting nudge
- introduce wd_should_throttle and wd_mark with cooldown tracking
- throttle and mark actions in QC, export, aggregation, analytics flows
- add ghostwriting narrative nudge for expanded sections
- include watchdog fields in scans and streamline updates
- export/qc messaging enriched with stable options and keys
- minor refactors for cloning keys and utility visibility
ci(workflow): add env input and deploy-test job; refine triggers (#29)
- add workflow_dispatch input to select dev or test environment
- gate deploy-dev on target_env=dev for manual runs
- introduce deploy-test job with ECR build/push and CFN deploy
- clean up redundant comments and blank lines in workflow
- update CloudFormation test AllowedOrigins to test.bookcicle.com
What the tool enforces (so you don’t have to)
Where it fits in your Git strategy
This has been surprisingly neutral and helpful across styles. Here’s how we use it (and what we recommend):
1) Linear history (rebase & merge)
Recommendation: Use --strict for atomic commits. Enforce fast-forward merges and Conventional Commits in CI.
2) Squash-and-merge (clean main, messy branches) - our favorite
Recommendation: Make PR descriptions the source of truth. Set your platform to “Use PR title & description” on squash.
3) Merge commits (the “graph tells the story” crowd)
Bottom line: We default to linear on main for signal, but commitmsg delivers value for any merge policy—as long as you pick one and stick to it.
A peek at the prompt (commit mode)
We keep it short and bossy:
That’s it. No essays, no fluff.
What changed for us
(We didn’t gold-plate with vanity metrics; the qualitative lift was obvious within a sprint.)
Try it & tell us what breaks
If you want to kick the tires, check out bookcicle/commitmsg on GitHub and open an issue or PR. We’re already exploring pre-commit hooks, CI guards for Conventional Commit headers, and optional release-note generation.
Happy shipping—and happy reading those commit messages. 🧹✨