Skip to content

Normalize costs and find dead seats

Once two or more harnesses are emitting through Trove, their signals all arrive in the same normalized Tier A schema. That’s what makes them comparable: trove.harness.cost.usd from Claude Code sits on the same axis as trove.harness.cost.usd from GitHub Copilot CLI, with no vendor-specific exporter to build or maintain. Two questions get easy to answer:

  • Where is the money going? Compare spend per tool, per user, per week — apples to apples.
  • Which paid seats are dead? Find licenses with zero activity so procurement can act before renewal.
MetricUse it forKey attributes
trove.harness.cost.usdSpend, normalized across vendorsmodel, cost.method (exact / estimated)
trove.harness.eventsActivity — turns, tool calls, editsevent.kind
trove.harness.tokensVolume behind the spenddirection, model

Every data point also carries resource attributes set per harness: harness.id, harness.name, and — once you’ve added identity tagsuser.name and user.email. Those are the dimensions you group by.

The goal is a single chart where each AI tool is a comparable series.

  1. Enable the harnesses you want to compare and confirm each is flowing (its harness.id shows up in the Logs tab and at your backend). Mixed coverage is fine — native-OTel and watcher-based harnesses both emit Tier A.

  2. Make sure cost is being emitted. On the Mappings tab, check that each harness’s cost.usd row is enabled. Where Trove can’t get a real cost from the harness it estimates from tokens and the rate table, marking those points cost.method = estimated. Set your own model prices in the rate table if you run a custom or self-hosted model.

  3. Build a “spend by tool” view in your backend: sum trove.harness.cost.usd grouped by harness.id over a time window. Because the schema is shared, each harness becomes one comparable series in the same panel.

  4. Split exact vs. estimated by also grouping on cost.method so you know how much of the number is metered versus modeled. Estimated rows are directional; exact rows are billable-grade.

  5. Derive cost per turn by dividing trove.harness.cost.usd by the chat.turn slice of trove.harness.events (filter event.kind = "chat.turn"), grouped by harness.id. Now “cost per interaction” is directly comparable between, say, Claude Code and Cursor.

A “dead seat” is a paid license that produced no activity in a window. The same harness.id-keyed (and, with identity tags, user.email-keyed) stream that powers your cost dashboard surfaces them.

  1. Tag signals with identity. In Settings, set user.name and user.email so each person’s activity is attributable. Roll this out across the team so the per-user view is complete. See Add identity tags.

  2. Define “active.” Pick a metric and window that mean “this seat is being used” — for example, at least one trove.harness.events point with event.kind = "chat.turn" in the last 30 days.

  3. List who fired. In your backend, query the active set: distinct user.email (optionally per harness.id) with at least one qualifying event in the window.

  4. Subtract from your roster. Compare that active set against your license roster for each tool. Anyone holding a paid seat who isn’t in the active set is a dead-seat candidate — by user, by tool, by week.

  5. Act before renewal. Hand the list to procurement. Reclaiming a handful of unused Cursor or Copilot seats across a large org is often the fastest payback Trove delivers.

Trove does the normalization at the collector, so your backend never sees five vendor dialects — it sees one Tier A schema with consistent attribute names. That’s the difference between “four dashboards nobody reconciles” and “one query that compares everything,” and it’s what lets finance and engineering look at the same numbers.