Building an Agent Spend View Your Finance Team Will Actually Read

A worksheet for connecting coding-tool subscriptions, model usage, review effort, rework, and build activity to accepted changes, using your own invoices instead of borrowed benchmarks.

Jordan Patel|15 min

It is renewal season, and the invoices for your AI-assisted development stack are spread across four different owners. Assistant seats. Model API usage. CI minutes. A scanning tool that started charging per pull request somewhere along the way. The question from finance is simple and reasonable: what did that buy us?

The honest answer most engineering leaders can give right now is a shrug dressed up as a percentage borrowed from someone else's report. That does not survive a second question.

An agent spend view is a worksheet, not a dashboard. It divides five cost lines (subscriptions, metered model usage, review effort, rework, and build activity) by one defined output unit (accepted changes), reported at a level where someone can actually act on the result. You fill it with your own invoices, your own pull request history, and your own internal rates. This article gives you the worksheet, the definitions that stop arguments, and the places the data actually lives.

The Invoice Nobody Can Explain

The invoices arrive separately, on different cycles, owned by different people. Assistant seats usually sit with a platform or IT budget. Model API usage lands in a cloud or provider console that engineering opened for a pilot and nobody re-owned. CI minutes are buried in the same platform bill as repository hosting. Scanning and observability tools often sit with security.

Nobody sums them, because summing them without a denominator produces a number that only looks bad. Some large figure per month, for what? Compared to what?

This is where borrowed benchmarks fail hardest. A published productivity percentage describes someone else's repositories, review standards, test coverage, and rework rate. If their reviewers approve quickly and yours hold a two-round review on payment paths because a bad change costs real money, the percentage transfers nothing. Worse, quoting it invites finance to hold you to a number you did not generate and cannot reproduce.

The alternative is unglamorous and durable. Define one output unit. Enumerate five cost lines. Pick a reporting level. Write down the assumptions on the same page as the result. You will not get a benchmark. You will get a number you can defend line by line, which is the only kind that survives a finance review.

Pick the Output Unit Before You Total the Costs

Choose the denominator first, or the cost total will quietly choose it for you.

The unit I recommend is the accepted change: a pull request merged to a protected branch, with required checks passing, with a required review recorded, and not reverted or hotfixed within a stated window. Every clause in that sentence is doing work. Merged to a protected branch excludes long-lived experiment branches. Required checks passing and required review recorded mean the change went through your defined path rather than around it. The revert window means you are counting changes that held.

Consider the alternatives and why they break:

- Deploys measure release cadence, not change volume. A team that batches many changes into one deploy looks dramatically cheaper than a team that ships continuously, for no real reason.

- Story points are estimates of effort, not units of output, and they are not comparable across teams by design.

- Lines of code get worse the more capable your tooling gets. A model that emits a long implementation where a short one would do makes your cost per line look excellent.

- Commits reward noise. Agent retries on the same intent inflate the count without adding value.

Then write your exclusion rules down, because they will be challenged. I exclude automated dependency bumps, generated lockfile updates, formatting-only commits, and repeated agent attempts at the same intent where only the final merged attempt counts. Reasonable teams draw these lines differently. Unreasonable teams draw them differently every quarter.

One more discipline: never report cost per accepted change alone. DORA's research program frames delivery throughput and stability as measures that have to be read together, because optimizing one while ignoring the other produces a distorted picture of performance [1]. A cost-per-change number that falls while change failure rate climbs is not an improvement. It is a bill arriving later.

Here is the shape of the calculation, so you can see the method rather than a result. Take your platform's count of merged pull requests for the month. Apply the exclusion rules to remove dependency bumps, lockfile churn, formatting commits, and duplicate agent attempts. What remains is your accepted-change count. Substituting your own two numbers matters more than any illustrative pair I could print. What matters is that the same rules produce both numbers next month.

The Five Cost Lines That Belong in the View

Five lines cover almost everything, and the last two are the ones teams skip.

Subscriptions are per-seat charges for coding assistants, review tooling, and anything else billed by headcount. Pull this from your own billing export, and pull the activity data alongside it. Seats assigned but unused are the single most common finding in a first-pass spend view, and they are also the easiest to act on before a renewal conversation.

Model usage is metered token or request spend from agent runs. Split it into authoring workloads and review workloads if your tooling lets you tag them, because those two categories respond to completely different interventions. Authoring spend follows developer behaviour. Review spend follows pull request volume and diff size.

Review effort is reviewer hours converted at a fully loaded internal rate that you supply. Include re-review rounds, which is where the real cost hides. A change that takes three rounds costs more than three times a single-round change, because context is lost between rounds.

Rework is reverted or hotfixed changes inside your stated window. Build activity is CI minutes, runner costs, and check reruns attributable to agent-opened pull requests. I group these as one line in reporting and two in collection, because they usually move together: changes that come back also burn pipeline time on the way.

Cost lineWhere the number comes fromWho owns itUpdate cadenceCommon measurement trap
SubscriptionsVendor billing export plus admin activity reportPlatform or IT budget ownerMonthly, reconciled at renewalCounting assigned seats as active seats
Model usageProvider billing console, tagged by workloadEngineering platform leadMonthlyMixing authoring and review spend into one figure
Review effortPR review events and timestamps, times internal rateEngineering manager per teamMonthlyIgnoring second and third review rounds
ReworkReverts and hotfixes within a stated windowSame owner as review effortMonthly, with a lagging windowClosing the month before the revert window expires
Build activityActions or Runners usage report, filtered to PR workflowsCI ownerMonthlyAttributing scheduled jobs to pull requests

The internal rate is yours to set and yours to publish. Whatever finance already uses for fully loaded engineering cost is the right input, because arguing about the rate is not a conversation engineering wins or needs.

Choose a Reporting Level Someone Can Act On

Pick the level by asking who reads the number and what they are allowed to change.

Repository level exposes which codebases absorb disproportionate review and rework cost. This is the most operationally useful level, because the fixes are concrete: adjust ownership routing, tighten merge conditions, add a check, split a service.

Team level supports staffing and tool allocation. It answers whether a squad's tooling spend tracks its output, and it is the level a director can act on in a planning cycle.

Organization level supports renewal negotiation and portfolio decisions. It is the only level finance genuinely needs, and it is nearly useless for diagnosis.

Do not report per developer. The moment an individual's cost per change becomes visible to their manager, the data quality collapses. People will split pull requests, avoid hard repositories, and stop asking for review. You will have converted a spend view into a performance review and lost both.

Scope boundary
Name the repositories, branches, and change types included, and what is deliberately out
Denominator definition
Write the accepted-change rule and its exclusions on the same page as the number
Paired stability measure
Read cost per change alongside a stability measure, never alone [1]
Exception owner
Name one person who rules on repositories with legitimately expensive review paths
Revisit date
Set the date you will re-examine definitions, before anyone builds a dashboard
Reporting levelQuestion it answersData you needWho reads itBest for
RepositoryWhich codebases absorb review and rework costPR history, check results, CODEOWNERS routingTech leads, platform teamDiagnosis and targeted fixes
TeamDoes tooling spend track this team's outputSeat assignments, team-scoped PR dataEngineering managers, directorsStaffing and tool allocation
OrganizationWhat is the total and what changes if we cutAll five cost lines, rolled upCTO, finance, procurementRenewal and budget decisions
Per developerNot recommendedN/AN/ANothing. It degrades the data you need

Filling the Worksheet: A Two-Repository Walkthrough

Two repositories in the same organization can produce the same cost per accepted change for opposite reasons. That is the argument against a single blended number, and it is easiest to see concretely.

Scenario A: the payments service

High review effort per change. Every pull request touching the settlement paths draws two reviewers, and a substantial share go to a second round. Model usage is modest because the diffs are small and carefully scoped. Rework is low, which is the point of the review depth.

The arithmetic: accepted changes for the month, divided into subscription share plus model usage plus (reviewer hours times your internal rate) plus build minutes. Reviewer hours dominate. The cost per change looks high, and it should, because the review path is doing deliberate work where a wrong change is expensive.

What to change here is routing, not depth. If review requests are landing on whoever is available rather than whoever holds the decision history for those paths, you are paying for expensive review that lacks the context to be efficient. Path-based ownership files exist for exactly this: they route a pull request to the people responsible for a given directory [2]. Tightening CODEOWNERS on the settlement paths reduces rounds without reducing scrutiny.

Scenario B: the internal admin app

Cheap review, high rework. Single approver, fast merges, low model spend. But reverts and hotfixes inside the stated window run high enough that rework becomes the largest line in the view.

Here the cost is real but deferred, which is why teams miss it. The fix is merge conditions rather than more human review time: required checks that actually fail on the class of defect causing the reverts, expressed as organization-level rule sets rather than per-repository settings that drift [3]. Verify enforcement empirically by attempting a merge that should be blocked, because configuration that looks correct and behaviour that is correct are different claims.

A Blended Org Number Hides Both of These
Average the payments service and the admin app together and you get a middling cost per accepted change that suggests no action. One repository needs better review routing. The other needs stricter merge conditions. The blended figure recommends neither. Always compute at repository level first, then roll up for finance.

Where the Data Actually Lives (and Where It Does Not)

Every line in the worksheet maps to a real system, and the mapping is worth writing down before anyone builds anything.

Pull request events, review records, and check conclusions come from your GitHub or GitLab history. CI minutes come from Actions or Runners usage reports. Model usage comes from the provider billing console. Seat activity comes from your assistant admin tooling, which is where inactive seats surface [4].

Retention is a hard constraint, not a detail. If pull request and check history ages out of your platform or your export pipeline before your reporting window closes, the view cannot be rebuilt later. NIST's secure software development guidance treats archiving the evidence that practices were followed as a practice in its own right, separate from defining the practices [5]. Check your actual retention against your actual reporting window before you promise finance a quarterly view.

For artifact-level questions, emit build provenance as a pipeline by-product. A signed statement describing what was built, from which source, by which builder, removes an entire category of manual reconstruction later [6]. This matters for the spend view because linking rework back to the change that caused it is otherwise archaeology.

Now the part to say plainly: do not try to measure what share of a diff a model wrote. It is not mechanically verifiable, and any number you produce will be an estimate dressed as a measurement. Measure review depth and check outcomes instead, both of which are observable. That is the same discipline that applies to audit evidence for AI-assisted changes, and it is why SlopBuster's context-aware pull request review reports on what the review found rather than guessing at authorship proportions.

A monthly extract that gets two of your five lines into real numbers looks roughly like this:

bash
# Merged PRs for one repo, last month, with review and check state
gh pr list \
  --repo your-org/payments-service \
  --state merged \
  --search "merged:2026-01-01..2026-01-31" \
  --limit 500 \
  --json number,title,mergedAt,author,reviews,statusCheckRollup \
  > merged-prs-2026-01.json

# Count accepted changes after exclusions
jq '[.[]
  | select(.title | test("^(chore\\(deps\\)|bump |Update lockfile)"; "i") | not)
  | select(.reviews | length > 0)
  | select(.statusCheckRollup | all(.conclusion == "SUCCESS"))
] | length' merged-prs-2026-01.json

Run it once by hand before you automate it. You will discover your exclusion pattern is wrong, and it is cheaper to discover that in a terminal than in a board deck.

Making the Number Survive Its First Finance Review

The first question finance asks is never about the number. It is about the method.

Put the denominator definition, the exclusion list, the internal rate, and the revert window on the same page as the result. If those four things are not visible, the conversation becomes an interrogation about how the number was made, and you will spend the meeting defending arithmetic instead of making a decision.

Separate committed from variable cost. Annual seat commitments are not reducible this quarter no matter what the view says. Model usage, CI minutes, and check reruns are. Finance cares intensely about this distinction, because it determines whether a decision changes cash flow or just changes a slide.

Renewal inputBefore the viewAfter the viewDecision it enables
Seat countHeadcount-based estimateAssigned versus active seats, by teamRight-size before signing, not after
Model usageOne provider invoice totalSplit by authoring and review workloadCap or tier the workload that grew
Review costNot measuredReviewer hours per repositoryFix routing on the expensive paths
ReworkInvisibleReverts and hotfixes per repositoryTighten merge conditions where they pay
Build minutesBundled platform linePR workflow minutes, attributableCut reruns and redundant required checks

One cadence, one owner. Monthly is right for most organizations, with a lagging revert window so you are not closing a month before rework has had time to appear. Name the person who rules on exceptions, such as a repository whose review path is expensive on purpose. Without a named owner, every anomaly becomes a debate.

Finally, resist using this view to justify headcount changes in its first two quarters. Measurement noise is highest early, definitions are still settling, and a staffing decision made on a definition you later change is a decision you cannot explain. Use the first two quarters to stabilize the method. Use quarter three onward to make decisions. Tracking which repositories carry disproportionate ownership and rework risk is a separate and complementary exercise, which is where repository and contributor intelligence earns its place next to the spend view.

Frequently Asked Questions

Is cost per accepted change a productivity metric?

No. It is a spend allocation metric. It tells you where money goes per unit of shipped change. It says nothing about whether those changes were the right ones to make, and it should never be read without a stability measure alongside it [1].

What revert window should we use?

Two weeks is a reasonable default for most web and service codebases. Pick one, write it down, and keep it constant. Changing the window changes the number, so changing it mid-year destroys comparability.

Should agent-opened pull requests be counted separately?

Count them separately in collection, together in the denominator. You want to know whether agent-opened changes carry different review and rework profiles, but a change that shipped is a change that shipped regardless of who opened it. Enumerate every identity that can open or merge, including bot and agent accounts, and confirm none of them has a bypass path around required conditions [3].

Do we need the decision context in the repository for this to work?

Not for the arithmetic, but it changes the results. Architecture decision records are a lightweight, version-controlled way to capture the context and consequences of a choice next to the code it governs, rather than in an external wiki [7]. When that context lives only in meeting notes, review rounds multiply because reviewers reconstruct it each time. Repository-resident decision records and typed institutional memory in Genie both attack the same cost line: review effort.

What if our model usage is not tagged by workload?

Start with the single total and split it next quarter. An untagged line you actually report beats a tagged line you keep meaning to build.

How do the five cost lines relate to review quality?

Review effort and rework are the two lines that move in opposite directions, and that is the useful tension in the worksheet. Cutting reviewer hours lowers one line and tends to raise the other after a lag, which is why the view only makes sense read as a whole and paired with a stability measure [1]. The practical lever is usually context rather than time: routing a change to the people who hold the relevant decision history reduces rounds without reducing scrutiny [2]. Our write-up on the hidden costs of code review bottlenecks covers where that queue time accumulates.

What to Do in the Next Thirty Minutes

Four concrete steps, in order.

1. Pull one repository's merged pull request count for last month and apply your exclusion rules. You now have a first accepted-change number and, more importantly, a first draft of the exclusion rules.

2. Export one billing statement and one CI usage report. Two of five cost lines become real instead of estimated, and the gap between the two tells you which data source needs work.

3. Pick the reporting level and name the definition owner before anyone opens a dashboard tool. The dashboard is the last step, not the first.

4. Start tracking reverts and hotfixes within your chosen window, starting this week. Rework is the line most teams omit and the line that most often explains an anomaly. It is also the only line that requires you to wait, so start the clock now.

Then go back to those four invoices you could not reconcile. With the worksheet filled, the answer is not a percentage from someone else's report. It is this: last month we accepted this many changes across these repositories; the cost per accepted change was this, composed of these five lines; two repositories account for most of the variance, one because its review path is expensive on purpose and one because its merge conditions are too loose; here is what we are changing before renewal, and here is what we are not.

That is an answer a finance team will read.

References

[1] DORA, "DORA Research Program." https://dora.dev/research/

[2] GitHub, "About code owners." https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners

[3] GitHub, "About rulesets." https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/about-rulesets

[4] GitHub, "GitHub Copilot documentation." https://docs.github.com/en/copilot

[5] NIST, "SP 800-218, Secure Software Development Framework." https://csrc.nist.gov/pubs/sp/800/218/final

[6] SLSA, "Provenance specification, version 1.0." https://slsa.dev/spec/v1.0/provenance

[7] Architecture Decision Records community, "Architecture Decision Records." https://adr.github.io/