You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(spend): subscription seats - flat fees as real spend, usage value as leverage
* docs(readme): survival-based coding ROI + live demo link
The feat(roi) change dropped the merged-PR metric and hid github_pr from
the outcome picker, but only updated in-app help. Bring the README in
line: coding rows are accept rate + revert + 30-day line survival, GitHub
is a routing container, and the outcome list drops github_pr. Also add the
live read-only demo at tokenturn-demo.flowengine.cloud.
* feat(spend): subscription seats - flat fees as real spend, usage value as leverage
Separate what you pay from what the usage is worth. Flat subscription seats
(Claude Max $20/$100/$200, a Cursor/Copilot seat) are recorded at their fixed
monthly fee as real spend (new billing_mode 'subscription'), while the seat
holder's usage shows as usage value from the vendor's OWN per-model estimate -
never our table, never double counted (a subscription customer is not API-billed).
- billing_mode axis on spend_facts/rollup_daily; subscription_seats registry +
monthly materializer (lib/seats.ts), mirroring the invoice true-up
- Overview: real spend (Subscriptions/Metered split) + usage value with the
leverage delta; billing_mode drill filter; seats API (GET/POST/DELETE)
- Settings card to add/price/remove seats, Claude plan presets, and
auto-detected candidates from identities.subscription_type
- Anthropic connector stamps subscription_type per Claude Code user
- Demo seeds three real Claude tiers; seat usage value priced through the real
per-model table (no magic multiplier)
Also squash all 19 migrations into one clean 001_core_schema.sql, verified
catalog-identical to the incremental build.
* test: update fixtures for subscription seats + migration squash
- overview.test: new totals fields (subscription/metered/usageValue)
- schema.test: list the subscription_seats table
- auth.test: drop the 017-backfill test (that one-time upgrade migration is
folded into the squashed schema; fresh installs have nothing to backfill)
Copy file name to clipboardExpand all lines: README.md
+9-5Lines changed: 9 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,22 +2,26 @@
2
2
3
3
Self-hosted AI spend and ROI ledger. No proxy, no stored keys.
4
4
5
+
**[Live demo](https://tokenturn-demo.flowengine.cloud/)** - the whole product, read-only, on six months of seeded data. The login is pre-filled, so just click sign in.
6
+
5
7
Tokenturn has two main goals:
6
8
7
9
1.**Calculate the actual benefit you get for your AI spend.** What an agent that costs $200/month actually delivers, and whether it meets your success criteria. How much of the code written by AI survives production.
8
10
2.**Manage all AI spend across employees and tools.** Set per-person limits, catch burn spikes, invite and offboard people across vendors in one click, and true your estimates up against real invoices.
9
11
12
+
Spend is shown two honest ways, never mixed. **Real spend** is what you actually pay: pay-as-you-go API usage plus flat subscription seats (a Claude Max $20/$100/$200 seat, a Cursor/Copilot seat) recorded at their fixed monthly fee, not as a per-token guess. **Usage value** is what that usage would cost at API rates - on a flat seat it runs well above the fee, and that gap is the leverage the plan buys. Filter any view by metered vs subscription. ROI still uses the dollar figure; total spend reflects the real fee.
13
+
10
14
For ROI we calculate three different ways:
11
15
12
-
1.**Coding (built in).** Connect Cursor, Copilot, or Anthropic and you get merged PRs, accept rate, revert rate, and line survival (% of AI-written lines still alive after 30 and 90 days) with zero setup. Agents like Devin route their whole spend to one ROI row.
16
+
1.**Coding (built in).** Connect Cursor, Copilot, or Anthropic and you get accept rate, revert rate, and line survival (% of AI-written lines still alive after 30 and 90 days) with zero setup - coding ROI is survival, not merge count. Agents like Devin route their whole spend to one ROI row.
13
17
2.**SDK wrap.** Wrap your OpenAI/Anthropic client with the TypeScript or Python SDK. Every call is counted from the response usage, and `track()` records a success and its value when your tool delivers.
14
18
3.**API track.** Send events straight to `POST /api/ingest` from anything that can make an HTTP call. No SDK needed.
15
19
16
20
## Why Tokenturn
17
21
18
22
-**No proxy.** Proxying your LLM keys adds a bottleneck, latency, maintenance, a point of failure, and a real security risk. Tokenturn reads the vendors' admin APIs instead - nothing sits between your apps and the models.
19
23
-**No stored keys.** Your employees' API keys never pass through Tokenturn. Vendor admin tokens are stored encrypted; keys minted for people are shown exactly once and never saved or logged.
20
-
-**Flexible.** You define ROI your way: any spend slice (a tagged key, the SDK, a whole vendor, manual) against any success definition (`track()` events, merged PRs, manual), with your own value per outcome. The whole reports exports as [FOCUS] so any FinOps tool can ingest it.
24
+
-**Flexible.** You define ROI your way: any spend slice (a tagged key, the SDK, a whole vendor, manual) against any success definition (`track()` events, issues done, manual), with your own value per outcome. The whole reports exports as [FOCUS] so any FinOps tool can ingest it.
21
25
22
26
## Integrations
23
27
@@ -66,7 +70,7 @@ Seven pages behind one global date-range picker (the range lives in the URL, so
66
70
67
71
-**Overview** - total spend with its estimated/invoiced split, attribution coverage, daily trend, spend by vendor, top people, top ROI rows, connector health.
68
72
-**People** - everyone (plus the visible Unassigned bucket) with spend by vendor, outcomes, and $/outcome. A person's page shows their keys, seats, daily breakdown, and the ROI rows they touch.
69
-
-**ROI** - every ROI calculation in one list with the same columns: spend, tokens, successes, $ per success, value, ROI multiple. The built-in coding rows carry merged PRs, accept rate, revert rate, and line survival. A row with no success metric shows plain cost - never a fake ROI.
73
+
-**ROI** - every ROI calculation in one list with the same columns: spend, tokens, successes, $ per success, value, ROI multiple. The built-in coding rows carry accept rate, revert rate, and line survival - success is surviving code, not merge count. A row with no success metric shows plain cost - never a fake ROI.
70
74
-**Resolve** - the identity queue: confirm matches, route service accounts, merge two emails into one human. The nav badge drains live.
71
75
-**Report** - one printable CFO page per month that always sums to the whole ledger. Exports as CSV or [FOCUS 1.4](https://focus.finops.org).
72
76
-**Settings** - five tabs: Personal API keys, Connections (vendors, Jira/Linear, SDK keys, email, Slack), Alerts, Data, License.
@@ -78,7 +82,7 @@ Connectors sync hourly with a stored cursor: full backfill on first connect, res
78
82
-**OpenAI** - org users, projects, and keys; daily usage and costs; invites, key minting, and removals. Needs an `sk-admin-...` key.
79
83
-**Anthropic** - org users and keys (self-minted keys auto-map to their creator), per-key daily usage priced from a pinned price table (marked `estimated` - Anthropic never reports dollars per user), and per-user Claude Code analytics. Needs an `sk-ant-admin...` key.
80
84
-**Cursor** - team roster, per-user spend and usage via the team Admin API. Limit pushes and member removal need the Enterprise plan.
81
-
-**GitHub** - Copilot seats, per-user AI-credit dollars (monthly grain), usage counters, and merged PRs as outcomes: AI authorship detected from bot authors and co-author trailers (Claude, Copilot, Cursor, Devin, Codex), and a revert within the window (default 30 days) flips the outcome. The same token feeds line survival: AI-added lines checked against the repo at the 30/90-day horizon. Survival comes from git - vendors report line counts, never which lines.
85
+
-**GitHub** - Copilot seats, per-user AI-credit dollars (monthly grain), usage counters, and line survival as the coding outcome: AI authorship detected from bot authors and co-author trailers (Claude, Copilot, Cursor, Devin, Codex), AI-added lines checked against the repo at the 30/90-day horizon, and a revert within the window (default 30 days) drops those lines. GitHub is a routing container here - the visible ROI is per-tool surviving code, not spend-per-merge. Survival comes from git - vendors report line counts, never which lines.
82
86
-**Jira / Linear** - success only, never spend. Each issue runs a state machine over its real status-transition history: hits the submitted status, goes pending; survives the window (default 30 days) or reaches Done, success; regresses inside the window, fail. Agent actors (app users) get the credit when they're the issue's delegate, assignee, or creator, and route to an ROI row by tag or by project mapping.
83
87
84
88
Every endpoint is verified against current vendor docs and covered by fixture tests, but most need real credentials to exercise live (admin keys for OpenAI/Anthropic/Cursor, an org PAT for GitHub, provider credentials for email). Everything publicly callable was called live.
@@ -99,7 +103,7 @@ Key names become tags on the next sync - the name says what a key is for, by con
99
103
100
104
## ROI rows
101
105
102
-
An ROI row is anything that spends AI money: a name, a spend source (`connector`, `key`, `sdk`, or `manual`), and a success metric or none (`github_pr`, `sdk_event`, `manual`). The ROI page reads `GET /api/roi`; row CRUD keeps the old `products` path (`GET`/`POST /api/products`) - the table name stayed, only the language changed. A row can set a default value per outcome, applied at read time (changing it re-values history retroactively); per-event values override it. Tools with no API take manual monthly entries (`PUT /api/products/{id}/manual`) that drill down to the entry itself, not fake vendor rows. Archive is the only exit - history stays readable, nothing hard-deletes.
106
+
An ROI row is anything that spends AI money: a name, a spend source (`connector`, `key`, `sdk`, or `manual`), and a success metric or none (`issue_done`, `sdk_event`, `manual`); coding survival is built in. The ROI page reads `GET /api/roi`; row CRUD keeps the old `products` path (`GET`/`POST /api/products`) - the table name stayed, only the language changed. A row can set a default value per outcome, applied at read time (changing it re-values history retroactively); per-event values override it. Tools with no API take manual monthly entries (`PUT /api/products/{id}/manual`) that drill down to the entry itself, not fake vendor rows. Archive is the only exit - history stays readable, nothing hard-deletes.
0 commit comments