# Cost

> One number: cost per merged change. How it is measured from usage records, and what ModernCI charges.

## One number: cost per merged change

What it cost to get one change from an agent's "done" to merged: the machines and the agents, together. It comes from the record of usage, never from a projection. A number we don't measure is a number we don't claim.

cost per merged change = (machine minutes × price + agent spend) ÷ changes merged

- Machine minutes × price: per backend, by size; $0 on a reused result.
- Agent spend: tokens or cost the runtime reports.
- Changes merged: moves that reached their target.

Waste counts against it. A superseded run, a flake re-run or an idle warm machine bought nothing, so it raises the number. Quality lowers it. A right verdict the first time means no re-run and no wasted agent attempt.

## Before and after, measured (customer zero: our own monorepo)

Our own monorepo is a large Rust codebase with about 30 agent PRs open at any time, climbing four rungs to main. Both sides cover the same number of merged changes. Until the switch-over is done, this shows "before" and says so.

| | Before: GitHub Actions + homegrown engine | After: ModernCI |
|---|---|---|
| Machine minutes per merged change | measuring, from the Actions bill | at switch-over, from usage records |
| Agent spend per merged change | measuring, from host reports | at switch-over |
| Waste by class | ~2,000 runner-seconds per PR: 4 cold shards rebuilding the same tree | at switch-over |
| Done to merge, median | 8 h stalls with no alarm; a rung 10,000 commits behind for weeks | at switch-over |
| Cost per merged change | measuring | at switch-over |

## Every unit of work makes one record

Records are immutable, appended, and written before any status is posted, so no verdict goes unmetered. Everything goes on the record. Prices are applied on top: changing a price never changes a record. Export them with `modernci daemon usage`.

```json
{
  "id": "01JA9Q4M7X…",  "tenant": "acme",
  "repo": "monorepo", "move": "lane-search → predev", "check": "test",
  "kind": "run",
  "backend": "warm-2", "backend_owner": "tenant", "size": "large",
  "started": "2026-10-11T09:14:02Z", "ended": "2026-10-11T09:17:42Z",
  "minutes": 4, "saved_minutes": 0, "cost_actual": 0,
  "outcome": "green", "waste": "",
  "engine": "0.4.2", "config": "3f9c0e1"
}
```

Waste classes (work that bought nothing):

| Class | Meaning |
|---|---|
| superseded | A newer push made the run moot. |
| cancelled | Stopped before it judged anything. |
| duplicate | The same inputs, judged twice. |
| infra | A backend failed, not the code. |
| flake | A second witness: a re-run on another machine to confirm a flaky test. |
| warm_idle | A warm machine that waited for work. |

Budget caps per repo per day, a daily digest, and the biggest waste every 2 hours.

## Pricing: free on your machines, metered on ours

Pricing will be set from real usage records, like Actions but simpler: per minute by machine size. Numbers when we have them.

- Standalone daemon, your machines: $0. Free, forever. The whole product: the loop, the store, secrets, the UI and the operator MCP. It works with no cloud and keeps working if we vanish.
- Fleet on modernci.dev, many daemons, one view: metered. Connect any number of daemons with `modernci cloud connect`. Health, alarms, cost and waste across all of them. Code, logs and secrets stay home.
- Platform backends, our machines: per minute. Offered to any daemon as one more backend, by size. The router uses them only when they are the cheapest way to make the deadline.

| Size | On your machines | On our machines | Agent spend |
|---|---|---|---|
| small, medium | lower rate, set from records | one rate, set from records | shown, never marked up |
| large, xlarge | lower rate, set from records | one rate, set from records | shown, never marked up |
| gpu | lower rate, set from records | one rate, set from records | shown, never marked up |
| a reused result | $0 | $0 | none |
