Spend by user ·
Grouped from raw usage logs. “GritLift-paid” is what your pool key absorbed; BYOK is informational (the user paid it).
| User | Calls | GritLift-paid | BYOK | Features |
|---|
Spend by feature ·
| Feature | Calls | GritLift-paid | BYOK |
|---|
Spend by model ·
What each model actually costs in production. “Per call” is the number to compare when deciding whether a cheaper model is worth switching to — total spend just tracks how much that model happened to be used.
| Model | Calls | GritLift-paid | BYOK | Per call |
|---|
Most recent 200 calls. Failed calls never log — treat these totals as a floor and reconcile the pool key against the OpenRouter dashboard.
| When | User | Feature | Model | Tokens in/out | Cost | Key |
|---|
Every account holding the tester flag rides the pool key for free — the flag never expires on its own. opened within 3 days, within 14, gone quiet. “Last opened” needs an app build from 18 Jul or later; older installs show “—”.
| Who | Last opened | App | Workouts 30d | Last workout | Subs | Pool spend | Sub UI |
|---|
Sent from the app’s Send Feedback screen, newest first. “Actioned” = fixed in the product; “Duplicate” = closed without action (already reported); “Replied” = the person was told. “Reply” pre-targets the Messages composer at that person — your reply lands as a push + in-app banner.
| When | Who | Message | App | Status |
|---|
Which OpenRouter model each feature calls. Saved here, these take effect within a minute — no deploy, and no app update. Leave a field blank to fall back to the built-in default. Every call is logged with the model it used, so Spend and Logs can be filtered per model to compare cost and quality.
Model ids are OpenRouter's, e.g. anthropic/claude-sonnet-5,
deepseek/deepseek-v4-flash. A retired or mistyped id makes
that feature fail on every call — change one at a time and check Logs.
Models users can choose
Name and describe a model here and it appears in the app under Settings → AI → Grifter's model, as one global choice per user. In testing is visible to admins only; Available is everyone; Retired is nobody — it withdraws the model from use while keeping its description and validation record here, and anyone who had it selected falls back to the default on their next call. Retire rather than Remove unless you want the row gone entirely.
Before promoting anything to Available, validate it — Grifter is a tool
loop, and a model that is weak at function-calling doesn't look broken.
It answers beautifully and silently stops editing programs, setting
targets and saving memory. Run:
node scripts/validate-model.mjs <model-id> --write
and the result lands on the row below.
Live from the main site — the release script updates it on every build and OTA. Open full page
Writes a broadcast the app shows as a Home banner on next open (no push yet — that needs a binary with FCM). Targeting is client-side: never put secrets in one.
| Sent | Title | Target | Status |
|---|
Rollup ledger check ·
The app's own per-user monthly rollup (users/{uid}/aiUsage) vs the raw logs above. They should agree from Jul 2026 on; earlier months were never backfilled.
| User | Ledger GritLift-paid | Ledger BYOK | Raw GritLift-paid | Raw BYOK | Match |
|---|