Journal Metrics
AI coding cost per pull request: how to measure it without fooling yourself
Cost per pull request is the most intuitive AI spend metric — and the easiest to get wrong. How to compute it from OpenTelemetry cost and pull request counters, and the traps to avoid.
7 min read
Total AI spend tells you how big the bill is. Spend per developer tells you who is using the tools. Neither tells you whether the money is buying anything.
Cost per pull request gets closer. A pull request is the unit of work your team already reviews, merges and talks about in stand-ups, so “this PR cost $14 in AI” is a sentence everyone understands. It’s also easy to compute badly. This post covers how to measure it from data your coding agent already emits, and the traps that make the number lie.
The two ingredients
If you use Claude Code with OpenTelemetry metrics turned on (see our step-by-step OpenTelemetry setup), you already have both halves of the ratio:
| Metric | Unit | What it is |
|---|---|---|
claude_code.cost.usage |
USD | Estimated cost of model usage, per session, model and repository |
claude_code.pull_request.count |
count | Pull requests the agent created during a session |
Both are delta counters by default: each data point is the increase since the last export, so you sum them over any time window without diffing. Both carry session.id, and — on Claude Code v2.1.269 and later with OTEL_METRICS_INCLUDE_REPOSITORY=true — the repository attributes vcs.repository.url.full, vcs.repository.name and vcs.owner.name.
That gives you the simplest version of the metric:
cost per PR (repo, month) = Σ cost.usage / Σ pull_request.count
for that repository and month
It’s a fine start. It’s also where most dashboards stop, and where the problems begin.
Trap 1: the counter only sees PRs the agent opened
pull_request.count increments when the agent itself creates a pull request — typically by running your Git host’s CLI for you. If a developer works with the agent for two hours and then opens the PR by hand in the browser, the cost is recorded and the PR isn’t.
Teams differ wildly here. In one team every PR goes through the agent; in another, nobody lets it near git push. The naive ratio then makes the second team look ten times more expensive per PR when they’re doing exactly the same work.
Fix: use the counter as a cheap signal, but take the denominator from your Git host when you can — merged pull requests per repository per month. If you can’t, at least compare each team only against its own history.
Trap 2: opened isn’t merged
An agent-created PR that gets closed without merging still counts. So does the third attempt at the same change. If you divide by opened PRs, a team that churns through throwaway PRs looks cheap.
Fix: divide by merged PRs. Abandoned work isn’t free — its cost should land on the PRs that did ship, which is exactly what dividing total spend by merged PRs does.
Trap 3: cost before the branch exists
A lot of AI spend happens before there’s anything to open a PR for: exploring the codebase, reading a stack trace, prototyping an approach that gets thrown away. Sessions on main or with no repository at all are common.
Decide up front which spend counts:
- Repository-scoped: all spend attributed to the repository, divided by PRs merged there. Simple, and includes exploration.
- Branch-scoped: only spend on branches that produced a merged PR. Closer to “the cost of this change”, but needs branch context, which the agent doesn’t put on its metrics. A small
SessionStarthook can supply it — see cost per project for how.
Whichever you pick, show the remainder. Spend that can’t be attributed to any repository should appear as Unattributed, not silently vanish from the numerator.
Trap 4: the cost is an estimate, and maybe not cash
cost.usage is computed from token counts and list prices. It’s close to the invoice, not equal to it. If you need exact figures for finance, reconcile monthly against your provider’s cost reporting.
On seat-based plans the number isn’t money you paid at all — it’s the API-equivalent value of what was used. That’s still the right basis for comparing PRs, teams and months. Just don’t present “$11 per PR” to a CFO as cash out the door when the bill is a fixed seat price.
Trap 5: averages hide the expensive outliers
Cost per PR is heavily skewed. Most PRs are cheap; a handful cost more than everything else that week, usually one long session stuck in a loop or re-reading a giant context file.
Fix: report the median alongside the mean, and list the top five PRs or branches by cost. The outliers are where the useful conversations are.
Trap 6: comparing different kinds of work
A one-line config change and a database migration are both “one PR”. Comparing cost per PR across repositories with very different work is mostly comparing the work, not the efficiency.
Use it as a trend line within a repository. A stable $60 per PR on a gnarly legacy service is fine. The same service jumping from $25 to $90 in one week deserves a look.
A query you can actually run
If your metrics land in a SQL store with one row per data point, the repository-scoped monthly version looks like this:
select
repo,
date_trunc('month', ts) as month,
sum(value) filter (where metric = 'claude_code.cost.usage') as cost_usd,
sum(value) filter (where metric = 'claude_code.pull_request.count') as prs_opened_by_agent
from metric_points
where repo is not null
group by 1, 2
order by 2 desc, 3 desc;
Join merged_prs from your Git host on repo and month to replace the denominator, and keep the prs_opened_by_agent column as a sanity check: if it’s near zero for a busy repository, that team opens PRs by hand and the agent-only ratio means nothing for them.
What to do with the number
- Don’t make it a target. The moment cost per PR is a goal, people split PRs and stop using the agent for hard problems.
- Do use it to find waste. Sudden jumps, huge cache-creation token shares and long looping sessions are fixable.
- Do use it to price work. Agencies passing AI costs to clients find a per-PR or per-ticket figure much easier to explain than a monthly total — see billing AI costs to clients.
Or let us do the joining
SpendByTeam collects the same metrics, normalises repositories, adds branch and ticket from an open-source hook, and shows cost per project, ticket and PR out of the box. It receives metrics only — never code or prompts. Setup is one command per developer, and it’s free for up to 3 developers.