There's a strange pattern in how most of us use AI coding tools. We'll happily burn premium-model tokens writing a commit message — a task whose failure mode is "slightly awkward wording" — and then cheap out on the one prompt where a mistake costs us a production incident.
I did the opposite experiment for a month: I routed every low-stakes, high-frequency writing chore in my git workflow to free-tier models, and saved the expensive calls exclusively for work where being wrong actually hurts. The surprise wasn't that it saved money. It was that the chores got better, because I stopped doing them by hand at 6pm when my patience was gone.
This article is the setup: which chores qualify, the scripts, and the routing rule that keeps it honest.
The qualification test: reversible, verifiable, boring
Not everything belongs on the free tier. A chore qualifies only if it passes all three checks:
| Check | Question | Example pass | Example fail |
|---|---|---|---|
| Reversible | Can I undo a bad output in seconds? | Commit message draft | Migration script |
| Verifiable | Can I glance at it and know if it's wrong? | PR description summary | Regex for log parsing edge cases |
| Boring | Do I currently do it badly because it's tedious? | Changelog entries | Architecture decisions |
Three chores passed cleanly for me: commit message drafts, PR description scaffolding, and first-pass log triage. Notice what they share — a human reviews every one before it matters. The model isn't making decisions; it's removing the blank page.
Chore 1: Commit messages as a prepare-commit-msg hook
The prepare-commit-msg hook fires before your editor opens and pre-fills the message. Instead of a blank buffer, you get a draft you edit or delete:
#!/bin/sh
# .git/hooks/prepare-commit-msg
COMMIT_MSG_FILE=$1
COMMIT_SOURCE=$2
# Skip merges, squashes, and commits that already have a message
[ -n "$COMMIT_SOURCE" ] && exit 0
DIFF=$(git diff --cached --stat && git diff --cached | head -c 6000)
[ -z "$DIFF" ] && exit 0
DRAFT=$(mc-query "Write a conventional-commit style message for this diff.
Subject line under 72 chars, imperative mood, then a blank line and
a 2-3 sentence body explaining WHY, not what. Output only the message.
$DIFF")
if [ -n "$DRAFT" ]; then
echo "$DRAFT" > "$COMMIT_MSG_FILE"
fi
Here mc-query is a thin wrapper around whatever model endpoint you're using. Disclosure: This article was prepared as part of MonkeyCode's product outreach. In my case that wrapper points at MonkeyCode, whose free model access is what makes a hook like this psychologically sustainable — a commit hook fires on every commit, and I'd disable it within a week if each one had a meter attached. I run the wrapper against their free server option so the hook also works from a scratch VM or a CI runner without me copying credentials around.
The key design choice: the hook writes a draft into your editor, never a final message. You still read it. Most days I change two words; some days I delete it and write my own. Both outcomes are fine — the cost of a wrong draft is one keystroke.
Chore 2: PR descriptions from the branch, not from memory
The commit hook handles single commits; PRs need the whole branch. This script diffs against the base branch and produces a skeleton with the sections my team actually uses:
#!/usr/bin/env bash
# pr-draft.sh — run from your feature branch
BASE=${1:-main}
CONTEXT=$(git log --oneline $BASE..HEAD; echo '---'; git diff $BASE...HEAD | head -c 8000)
mc-query "Draft a PR description with exactly these sections:
## What changes (bullet list, one line each)
## Why (2-3 sentences)
## How to verify (numbered steps a reviewer can run)
## Risks (be specific; write 'none identified' only if true)
Base it only on the commits and diff below. Do not invent ticket numbers.
$CONTEXT" > pr-draft.md
The "How to verify" section is where this earns its keep. I used to write "tested locally" and move on. Now the draft forces concrete steps, and even when the model's steps are slightly off, correcting them takes thirty seconds and the reviewer gets something runnable.
One guardrail baked into the prompt: "Do not invent ticket numbers." Free models will cheerfully fabricate a plausible-looking PROJ-1234. Any placeholder in your team's conventions deserves the same explicit prohibition.
Chore 3: Log triage as a filter, not a verdict
When a deploy misbehaves, the first hour is usually scrolling. This one-liner classifies log lines into buckets so you scroll less:
journalctl -u myapp --since "1 hour ago" \
| grep -iE 'error|warn|exception' \
| head -200 \
| mc-query "Group these log lines by probable root cause.
For each group: a one-line hypothesis, a count, and the first timestamp.
Mark anything you are unsure about with [?]. Do not suggest fixes yet."
Two deliberate constraints here. First, head -200: this is a triage filter, and if 200 lines don't reveal the shape of the problem, the answer is in metrics or traces anyway, not more log. Second, "Do not suggest fixes yet" — unconstrained, the model jumps to confident remediation advice, and triage is exactly the moment you're most suggestible. Get the grouping first; decide the fix yourself.
The routing rule that keeps it honest
After a month, my split looks like this:
- Free tier: commit drafts, PR skeletons, log grouping, renaming things, writing throwaway scripts, "what does this error mean" lookups.
- Paid calls only: changes that touch money, data, or auth; anything I can't fully review in under five minutes; anything where a wrong answer is worse than no answer.
The rule isn't "free for small tasks" — it's "free for tasks where review is cheap and reversal is cheaper." A ten-line change to a billing calculation is small but stays on the paid tier. A 200-line PR description is large but stays free, because I'll read every word before it ships.
Where this breaks down
Be honest about the limits before copying this setup:
- Review discipline is load-bearing. The moment you start accepting commit drafts without reading them, the chore automation becomes a slow leak of nonsense into your history. If your team has a rubber-stamp culture, fix that first.
- Diffs leave your machine. The hook sends staged diffs to an external endpoint. If your code can't leave your perimeter, this whole article is moot — use a local model or nothing.
-
Free tiers are not an SLA. Free model access and free servers can be rate-limited, deprioritized, or discontinued. Every script above fails silently to manual behavior (
exit 0, empty draft) precisely so a bad day on the free tier means a blank commit editor, not a blocked workflow. Build that escape hatch into whatever you write. - This is not for low-commit-frequency work. If you commit twice a week, the hook saves you nothing and adds a dependency. The payoff scales with chore frequency.
What I actually learned
The interesting result wasn't cost. It was consistency: my commit history got noticeably more uniform, PR descriptions stopped being afterthoughts, and the 6pm version of me no longer writes "fix stuff" as a message. Cheap models on boring tasks beat good intentions, because they show up every time.
If you want to try the routing split without a billing dashboard watching every experiment, MonkeyCode's free models and free server are a low-commitment place to point the mc-query wrapper — the scripts above don't care what's behind it, so swap the backend whenever your needs outgrow the free tier.
Top comments (0)