Every few weeks a new model shows up with free access, and the same question cycle repeats: people try it on one throwaway prompt, get a decent answer, and either adopt it too fast or dismiss it too fast. Both reactions come from the same mistake — evaluating a model on a task that doesn't look like your actual work.
What follows is a lightweight evaluation routine I use before letting any model — free or paid — anywhere near my daily loop. It takes one focused afternoon, produces artifacts you can re-run later, and works against anything that exposes a chat-style HTTP endpoint.
The wrong way to evaluate
Single-prompt impressions fail for three reasons:
- Sample bias. The first prompt you think of is usually easy, because you already know the answer.
- No baseline. Without scoring, "seemed fine" and "seemed bad" can't be compared across models or across weeks.
- No regression signal. Providers change model behavior over time. If you can't re-run the same tasks, you can't notice when quality drifts.
The fix is boring on purpose: a fixed task set, a fixed rubric, and stored outputs.
Build a task set from your own commit history
Skip synthetic benchmarks. Instead, open your recent git log and reconstruct four to six tasks you genuinely solved. Good categories to cover:
| Category | Example task | What it reveals |
|---|---|---|
| Narrow edit | "Change this function's error handling to return Result types" | Instruction precision |
| Comprehension | "Summarize the data flow through this module" | Reading real code, not toy snippets |
| Generation with constraints | "Write a CLI flag parser, stdlib only, under 60 lines" | Constraint following |
| Debugging | "This test flakes roughly 1 in 20 runs. Hypothesize why." | Reasoning under uncertainty |
| Refusal behavior | Ask for something impossible or underspecified | Whether it hallucinates or pushes back |
Store them as JSON with a short scoring rubric per task:
[
{
"task_id": "flake-hunt",
"prompt": "This pytest test fails intermittently under parallel runs: [paste]. List the three most likely causes, ordered by probability, and what you'd check first for each.",
"rubric": {
"identifies_shared_state": 2,
"suggests_verification_steps": 2,
"no_invented_facts": 1
}
}
]
Numeric rubric items matter. "Good answer" is not a criterion; "names shared mutable state as a cause" is.
The runner: one file, no dependencies
Here's a minimal shell-based version using curl and jq — pick whichever toolchain you like, the principle is what counts:
#!/usr/bin/env bash
# eval.sh <tasks.json> — template; adjust URL, auth, and payload shape to your provider
set -euo pipefail
ENDPOINT="${EVAL_ENDPOINT:?set me}"
TOKEN="${EVAL_TOKEN:-}"
STAMP=$(date +%Y%m%d-%H%M)
mkdir -p "runs/$STAMP"
jq -c '.[]' "$1" | while read -r task; do
id=$(jq -r '.task_id' <<<"$task")
prompt=$(jq -r '.prompt' <<<"$task")
start=$(date +%s%N)
curl -sS --max-time 180 "$ENDPOINT" \
-H "Content-Type: application/json" \
${TOKEN:+-H "Authorization: Bearer $TOKEN"} \
-d "$(jq -n --arg p "$prompt" \
'{messages: [{role: "user", content: $p}], max_tokens: 1500}')" \
> "runs/$STAMP/$id.json"
end=$(date +%s%N)
echo "$id,$(( (end - start) / 1000000 ))ms" >> "runs/$STAMP/timings.csv"
sleep 2 # courtesy pause, especially on free access
done
echo "Outputs in runs/$STAMP — now score them by hand against your rubric."
Two deliberate design choices:
- Raw responses are saved verbatim. You can re-score old outputs when your rubric improves, without spending more tokens.
- Scoring is manual. For six tasks, auto-grading adds complexity without adding signal. Read the outputs, tick the rubric boxes, total the points.
Run the whole thing at least twice, on different days and ideally at different hours. Congestion on free infrastructure is real, and one lucky afternoon is not a service level.
Turning scores into a decision
After two or more runs, fill in a short scorecard per model:
- Task pass rate: what fraction of rubric points were earned, averaged across runs?
- Format obedience: did it respect "code only" / "under N lines" constraints?
- Honesty under uncertainty: on the impossible task, did it hedge, ask, or fabricate?
- Round-trip time: does the median latency fit your loop? (Batch refactoring tolerates seconds; inline autocomplete doesn't.)
- Sustainability: does the free access actually cover your realistic weekly volume, or will you hit a wall mid-project?
My personal rule: a model earns a spot if it passes on task quality and honesty, and its latency or availability limits only demote it to a different role (batch jobs instead of interactive use), not out of consideration entirely.
A concrete place to try this
Disclosure: This article was prepared as part of MonkeyCode's product outreach.
If you want a low-friction environment for the experiment, MonkeyCode is one option: according to its operator, it currently provides free model access together with a free server option. That pairing maps neatly onto this workflow — the server hosts the runner and the growing runs/ archive, and the free models become your evaluation candidates — without provisioning anything yourself or touching a credit card. I'm intentionally not naming specific models or quoting limits, because lineups and terms shift; verify what's offered in your own account before relying on it. The entire point of the scorecard is that you shouldn't trust anyone's quality claims, including a vendor's, without your own numbers.
If a free model clears your bar, the savings are immediate. If it doesn't, you lost an afternoon instead of discovering the mismatch three weeks into a project.
Where this approach breaks down
- It's a ranking tool, not science. Six tasks cannot characterize a model. It answers "which of these candidates fits my work" — nothing more.
- High-stakes domains need more. If wrong output costs money, safety, or legal exposure, you need formal evaluation, human review gates, and contractual guarantees. A free tier plus a shell script is not that.
- Nothing free is stable. Model lineups, rate limits, and server availability can change at any time. Treat every scorecard as time-stamped, and re-run before you build anything load-bearing on a free option.
- Task rot. Your work evolves; refresh the task set every month or two or you'll be grading against the developer you used to be.
Closing thought
Model debates in comment threads are unwinnable because everyone is answering a different question. A frozen task set plus a numeric rubric makes the question concrete, repeatable, and yours. Build it once, keep it under version control, and the next "should I switch models?" moment becomes a twenty-minute re-run instead of a week of waffling.
What's the one task from your own work that you'd consider non-negotiable on a scorecard like this? I'm guessing the debugging category would be controversial.
Top comments (0)