Saphan StudioDocs
Cost management

Worked examples

The commands, in the order the money actually moves: price it, check capacity, compose it, then read what it cost — and two refusals that cost nothing.

Every example below uses invoice-export as the name of the piece of work, and build-2 as the name of a machine. Substitute your own.

1. Price it, check capacity, then compose the dispatch

The budget bullets in the order are the decision, and the composer holds you to them:

- quote-usd: 5.00
- cap-usd: 10.00

Capacity before commitment — a report, and it cannot become a dispatch:

saphan fleet headroom --model sonnet --estimate-usd 5.00

Then compose the run. The prediction is a required argument, and the ceiling is derived from it rather than passed separately:

saphan dispatch command --stream invoice-export --machine build-2 \
  --model sonnet --cost-estimate-usd 5.00

2. The composer refusing a budget that disagrees with itself

Declare a ceiling in the order that is not twice the prediction, and composition stops with both numbers on the table:

dispatch-cap-usd-mismatch: order … declares `- cap-usd: 7.00` but the derived budget is
10.00 (2x the declared quote 5.00) — a composed command never silently picks one over the other
  reconcile the order's `- cap-usd: 7.00` bullet with --cost-estimate-usd 5 (2x = 10.00),
  or pass the --cost-estimate-usd the order's quote actually implies

Nothing runs and nothing is billed. ⇒ A disagreement between two people's numbers is resolved by a person, rather than by whichever code path read its argument last.

3. The routing gate earning its keep

saphan route channel-lint --policy ./routing.yaml --request-client

The step is routed to the deterministic tier by your routing policy, so the request for a model-capable context is refused — exit code 3 — and the refusal is booked in the ledger at zero. The cheapest rows in these books are the model calls that never happened.

4. Declaring who pays for a seat

saphan machine seat --identity finance-lane --machine build-2 --slot 1 \
  --backend codex --billing-class subscription --added-by platform-admin

Seating root-signs the seat's row, so it is run where the root key is held.

--billing-class takes exactly subscription, metered, or local-energy. ⛔ Anything else refuses with nothing written, and an omitted flag reads back as unknown — which anything gating spend treats as metered until somebody says otherwise.

⚠ Declaring the class on the seat does not by itself make that seat's runs book a real zero. That takes a matching row in the pricing registry, written by hand. The seat says who pays; the registry says what the rate is, or that there is no rate at all.

5. Read what one piece of work cost

saphan cost invoice-export

Per run: the actual in one normalised currency column, the prediction where one was recorded, and the difference where both are known — plus totals across continuations, and any unpriceable runs counted and named rather than counted as zero.

Because a stream closes into exactly one observed merge, this rollup is also the cost of the merged change: one piece of work, one merge, one number.

6. Read what the fleet cost

saphan ledger show
saphan ledger export > fleet.jsonl
saphan board export --format csv --csv streams --out fleet-report

The first is session and workspace totals — tokens in, out and cached, currency, calls, refusals. The second is every row and every dimension, one object per line, for your own reporting tool. The third carries the cost lanes into a report you can hand to somebody outside the team.

7. The register that keeps predictions honest

One row per prediction-and-actual pair, appended the day it happens, newest first, and ⛔ no row without a reference:

| date | work | act | actor and model | predicted | actual | difference, with cause | pass class | reference |

The pass class is one of first-pass, rework, refusal, manual-seam; the register is kept by hand, and the product does not record a pass class. The weekly question is not "how much did we spend" — that number is on the console already — but "what share of it was rework and manual seams, and is that share going down."

8. What a saved dollar looks like in the record

Three rows, all of which most cost tools would simply not have:

The rowWhat it tells you
A refusalA run refused before it spawned, recorded at zero with its reason
A named failure statusA run a provider limit ended — distinct from a vendor error, distinct from a ceiling hit, and never blended into the cost of the work it failed to deliver
A deterministic actBooked at zero, so the share of the work that needed no model at all is visible instead of merely absent

⇒ The books distinguish money spent on work, money spent on friction, and money the guardrails kept in your pocket. Only the first of those three appears on a vendor invoice.

Next