flagon-io/g1t

public

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t/packages/contracts/src/billing.ts

532 lines20,581 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Agents as a team: lifecycle, merge queue, billing and a new shell1import type { User, Viewer } from "./identity";
2import type { RepoPath } from "./repos";
3import type { Result } from "./result";
4
5/** Millionths of a US dollar in one dollar: the unit money is held in. */
6export const MICROS_PER_DOLLAR = 1_000_000;
7
8/** Whether workspaces are charged for agents at all, and with real money. */
9export type BillingStatus = {
10 /**
11 * False when no card processor is configured: nothing is charged, and who
12 * may run agents is decided some other way.
13 */
14 enabled: boolean;
15 /** False while the card processor is in its test mode, where cards are not real. */
16 live: boolean;
Free while g1t is being built out; agents can check out their own forks17 /**
18 * True while g1t is being built out: runs are recorded with what they
19 * cost, but nothing is charged and no credit is needed. Not forever.
20 */
21 free?: boolean;
Agents as a team: lifecycle, merge queue, billing and a new shell22};
23
24/** A workspace's standing. */
25export type BillingAccount = {
26 workspace: string;
27 /**
28 * Credit left, in millionths of a dollar. Can dip below zero by the cost
29 * of the runs that were under way when it ran out.
30 */
31 balanceMicros: number;
32 status: BillingStatus;
33 /** What is added to a run's cost, in percent. */
34 marginPercent: number;
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace35 /** The card charged near the limit and when a month closes, if one is saved. */
36 card?: { brand: string; last4: string; expMonth: number; expYear: number } | null;
Agents as a team: lifecycle, merge queue, billing and a new shell37};
38
39/** One line of a workspace's statement. */
40export type LedgerEntry = {
41 id: string;
42 /** Credit bought with a card, or an agent's run. */
43 kind: "top_up" | "usage";
44 /** Positive for credit added, negative for usage. */
45 amountMicros: number;
46 description: string;
47 /** For usage: the repository and pull request the agent worked on. */
48 repo: string | null;
49 number: number | null;
50 /** For usage: `implement`, `review` or `update`. */
51 task: string | null;
52 /** For usage: the model, by its public name. */
53 model: string | null;
Integrations: your own model provider, alerts that open issues, tickets agents read54 /** For usage: who paid the model provider. */
55 billedTo: "g1t" | "workspace";
Agents as a team: lifecycle, merge queue, billing and a new shell56 /** For a top-up: the username of whoever paid. */
57 createdBy: string | null;
58 /** RFC 3339. */
59 createdAt: string;
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace60 /** The workspace the line belongs to, which tells an enterprise's lines apart. */
61 workspace?: string | null;
Agents as a team: lifecycle, merge queue, billing and a new shell62};
63
64/** What lets a sandbox, and nothing else, report what its run cost. */
65export type RunTicket = { runId: string; token: string };
66
67/**
68 * What agents cost, charged to the workspace they worked for. A workspace
69 * buys credit; each run deducts its cost plus g1t's margin; with no credit,
70 * no agent starts.
71 */
A free allowance on g1t's models, so anyone can try its agents72/**
73 * The free allowance on g1t's hosted models for a workspace not otherwise
74 * open to them: a few dollars of model cost each, out of one pool, until a
75 * date. Mirrors `Trial` in `crates/contracts/src/billing.rs`.
76 */
Billing accounts, terms and enterprises; g1t is no longer free77/** How an account is charged. Standard unless g1t set otherwise in sudo. */
78export type Terms = {
79 kind: "standard" | "comped" | "custom";
80 discountPercent: number;
81 ceilingMicros: number | null;
82 note: string;
83 until: string | null;
84 setBy: string | null;
85 setAt: string | null;
86};
87
88/**
89 * Who pays: a workspace's own account, or an enterprise's, which pays for
90 * several workspaces with one bill and one limit.
91 */
92export type PayingAccount = {
93 id: string;
94 kind: "workspace" | "enterprise";
95 name: string;
96 terms: Terms;
97 workspaces: string[];
Stripe webhooks, enterprise invoices, and sudo for both98 /** Where an enterprise's invoices go. */
99 billingEmail?: string | null;
100 /** An enterprise's invoices, newest first. */
101 invoices?: EnterpriseInvoice[];
Billing accounts, terms and enterprises; g1t is no longer free102 createdAt: string;
103};
104
105export type AccountSummary = {
106 account: PayingAccount;
107 limit: Limit;
108 chargedMicros: number;
109 costMicros: number;
110 paidMicros: number;
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace111 /** The same figures for each of the account's workspaces that has any. */
112 byWorkspace: WorkspaceFigures[];
Two limits, real invoices, trust that grows by itself, sales signals113 /** The last six months, oldest first. */
114 months?: MonthFigures[];
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace115};
116
117/** One workspace's share of an `AccountSummary`. */
118export type WorkspaceFigures = { workspace: string; chargedMicros: number; costMicros: number; paidMicros: number };
119
Stripe webhooks, enterprise invoices, and sudo for both120export type StripeStatus = {
121 /** `test` or `live`, from the key; `off` without one. */
122 mode: "test" | "live" | "off" | string;
123 webhook: { url: string; endpointId: string; events: string[]; createdBy: string; createdAt: string } | null;
124 recentEvents: { id: string; kind: string; outcome: string; receivedAt: string }[];
125 error: string | null;
126};
127
128/** An enterprise's invoice: one line per workspace, paid on Stripe's page. */
129export type EnterpriseInvoice = {
130 invoiceId: string;
131 hostedUrl: string | null;
132 amountMicros: number;
133 status: "open" | "paid" | "overdue" | "void" | string;
134 period: string;
135 lines: { workspace: string; amountMicros: number }[];
136 createdAt: string;
137};
138
Two limits, real invoices, trust that grows by itself, sales signals139/** A workspace's invoice: monthly, or when charged near its limit. Itemised, in Stripe's billing page. */
140export type WorkspaceInvoice = {
141 invoiceId: string;
142 workspace: string;
143 reason: "month" | "threshold" | string;
144 period: string;
145 amountMicros: number;
146 status: "paid" | "open" | "failed" | "void" | string;
147 hostedUrl: string | null;
148 pdfUrl: string | null;
149 lines: { description: string; amountMicros: number }[];
150 createdAt: string;
151};
152
The statement is a month at a time, a line per kind of charge153/** A month of the ledger, grouped by day or project, a line per kind of charge. */
154export type Statement = {
155 month: string;
156 months: string[];
157 groups: {
158 key: string;
159 label: string;
160 lines: { kind: string; count: number; chargedMicros: number; costMicros: number }[];
161 chargedMicros: number;
162 }[];
163 totals: { chargedMicros: number; paidMicros: number; costMicros: number; entries: number };
164};
165
Two limits, real invoices, trust that grows by itself, sales signals166export type MonthFigures = { month: string; chargedMicros: number; costMicros: number; paidMicros: number };
167
168export type SignalKind = "at_limit" | "near_ceiling" | "declined" | "growing" | "established" | "first_payment" | "high_spend";
169
170/** Why a workspace is worth reaching out to. */
171export type Signal = {
172 workspace: string;
173 kind: SignalKind;
174 detail: string;
175 valueMicros: number;
176 stage: string | null;
177 owner: string | null;
Billing lists every invoice and every staff change; signals carry follow-ups178 nextStep?: string | null;
179 /** When the next step is due, YYYY-MM-DD. */
180 nextAt?: string | null;
181};
182
183/** One invoice g1t has sent, a workspace's or an enterprise's. */
184export type InvoiceSummary = {
185 invoiceId: string;
186 kind: "workspace" | "enterprise";
187 account: string;
188 name: string;
189 reason: string;
190 period: string;
191 amountMicros: number;
192 status: string;
193 hostedUrl: string | null;
194 createdAt: string;
195 paidAt: string | null;
Two limits, real invoices, trust that grows by itself, sales signals196};
197
198export type SalesStage = "none" | "lead" | "contacted" | "negotiating" | "won" | "lost" | "churn_risk";
199
200export type SalesRecord = {
201 workspace: string;
202 stage: SalesStage | string;
203 owner: string | null;
204 nextStep: string | null;
205 nextAt: string | null;
206 notes: { id: string; text: string; by: string; createdAt: string }[];
207 updatedAt: string | null;
208};
209
210export type Overview = {
211 month: string;
212 months: MonthFigures[];
213 byKind: { kind: string; chargedMicros: number; costMicros: number }[];
214 payingWorkspaces: number;
215 stopped: number;
216 nearCeiling: number;
217 declined: number;
218 openInvoicesMicros: number;
219 followUpsDue: number;
220};
221
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace222/** A customer's Stripe billing page, for staff to send them. */
223export type BillingLink = {
224 /** One-time and short-lived, signed in already. */
225 portalUrl: string;
226 /** The page's sign-in, which does not expire: the customer signs in by email. */
227 loginUrl: string | null;
228 customerEmail: string | null;
229 expiresNote: string;
Billing accounts, terms and enterprises; g1t is no longer free230};
231
232export type AdminAction = { id: string; account: string; action: string; detail: string; by: string; createdAt: string };
233
234export type AccountDetail = {
235 summary: AccountSummary;
236 workspaces: Limit[];
237 ledger: LedgerEntry[];
238 audit: AdminAction[];
239};
240
241/** Staff-only billing, for sudo.g1t.sh. Every change names who made it. */
242export interface BillingAdminApi {
243 accounts(query?: string): Promise<AccountSummary[]>;
244 account(id: string): Promise<Result<AccountDetail>>;
245 setTerms(id: string, terms: Terms, by: string): Promise<Result<PayingAccount>>;
246 createEnterprise(name: string, workspaces: string[], by: string): Promise<Result<PayingAccount>>;
247 attach(workspace: string, account: string | null, by: string): Promise<Result<PayingAccount>>;
248 credit(workspace: string, amountMicros: number, note: string, by: string): Promise<Result<LedgerEntry>>;
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace249 /** The workspace's Stripe billing page, to send to the customer. Logged. */
250 billingLink(workspace: string, by: string): Promise<Result<BillingLink>>;
Stripe webhooks, enterprise invoices, and sudo for both251 /** Where billing stands with Stripe; with `setup`, registers the webhook first. */
252 stripe(setup?: boolean, by?: string): Promise<StripeStatus>;
253 /** Where an enterprise's invoices go; makes its Stripe customer. */
254 enterpriseBilling(id: string, email: string, by: string): Promise<Result<PayingAccount>>;
255 /** Sends an enterprise its invoice now, for what its workspaces owe. */
256 invoiceEnterprise(id: string, by: string): Promise<Result<EnterpriseInvoice>>;
257 /** Exactly these workspaces' accounts, such as one page of the list. */
258 accountsFor(workspaces: string[]): Promise<AccountSummary[]>;
Two limits, real invoices, trust that grows by itself, sales signals259 /** Every workspace worth reaching out to, most urgent first. */
260 signals(): Promise<Signal[]>;
261 /** The business at a glance. */
262 overview(): Promise<Overview>;
263 /** A workspace's sales record. */
264 sales(workspace: string): Promise<SalesRecord>;
265 setSales(workspace: string, record: { stage: string; owner?: string | null; nextStep?: string | null; nextAt?: string | null }, by: string): Promise<Result<SalesRecord>>;
266 addNote(workspace: string, text: string, by: string): Promise<Result<SalesRecord>>;
267 /** A workspace's invoices from g1t, for staff. */
268 workspaceInvoices(workspace: string): Promise<WorkspaceInvoice[]>;
Billing lists every invoice and every staff change; signals carry follow-ups269 /** Every invoice g1t has sent, newest first. */
270 allInvoices(filter?: { status?: string; month?: string }): Promise<InvoiceSummary[]>;
271 /** Every change made in sudo and by Stripe, newest first, 100 at a time. */
272 audit(filter?: { by?: string; action?: string; before?: string }): Promise<AdminAction[]>;
Billing accounts, terms and enterprises; g1t is no longer free273}
274
Usage limits: unpaid usage can only go so far275/** How much a workspace has earned g1t's trust with money. */
Two limits, real invoices, trust that grows by itself, sales signals276export type Trust = "new" | "paid" | "established" | "reviewed" | "internal";
Usage limits: unpaid usage can only go so far277
278/**
279 * How far a workspace's unpaid usage has gone this month, and where its
280 * work stops: past `ceilingMicros`, no new sandboxes, builds or app
281 * requests. Usage counts at its cost to g1t or its charge, whichever is
282 * more, so it counts while g1t is free too.
283 */
284export type Limit = {
285 workspace: string;
Billing accounts, terms and enterprises; g1t is no longer free286 /** The account that pays: the workspace's own (`ws_<slug>`), or its enterprise's. */
287 account: string;
288 accountName: string;
Usage limits: unpaid usage can only go so far289 trust: Trust;
290 exposureMicros: number;
291 /** The lower of g1t's ceiling and the owner's spend limit; null for g1t's own. */
292 ceilingMicros: number | null;
293 trustCeilingMicros: number | null;
294 spendLimitMicros: number | null;
295 state: "ok" | "warning" | "stopped";
296 message: string | null;
Two limits, real invoices, trust that grows by itself, sales signals297 /** Charged this month: what the spend limit is measured against. */
298 spentMicros?: number;
299 /** True while the owners have not chosen a limit, so the automatic one applies: $200, or twice last month's spend. */
300 defaultSpendLimit?: boolean;
301 /** The most owners may set their own limit to; past it, they contact g1t. */
302 availableMicros?: number | null;
303 /** How the ceiling grows from here, in a sentence. */
304 growth?: string | null;
Usage limits: unpaid usage can only go so far305};
306
Prices keep themselves current with what g1t pays307/** One metered unit: what it costs g1t and what it is sold at; the price follows the cost. */
308export type Price = {
Agents and memory, checks and conflicts, profiles, slug renames, custom domains309 meter: "sandbox_second" | "build_second" | "app_requests" | "app_cpu" | "app_month" | "custom_domain_month" | string;
Prices keep themselves current with what g1t pays310 title: string;
311 unit: string;
312 costMicros: number;
313 markupPercent: number;
314 priceMicros: number;
315 /** `list`: Cloudflare's published price. `cloudflare`: measured from Cloudflare's bill. */
316 source: "list" | "cloudflare" | string;
317 checkedAt: string | null;
318 updatedAt: string;
319};
320
321export type PriceChange = {
322 meter: string;
323 oldCostMicros: number;
324 newCostMicros: number;
325 markupPercent: number;
Prices are what g1t pays plus 20%, from the first second326 /** The markup before, when the change was to the markup rather than the cost. */
327 oldMarkupPercent?: number;
Prices keep themselves current with what g1t pays328 reason: string;
329 createdAt: string;
330};
331
332export type PriceBook = { prices: Price[]; changes: PriceChange[]; modelMarginPercent: number };
333
A free allowance on g1t's models, so anyone can try its agents334export type Trial = {
335 open: boolean;
336 usedMicros: number;
337 limitMicros: number;
338 endsAt: string | null;
339 /** Why it is closed: `off`, `ended`, `used` (this workspace's) or `pool` (everyone's). */
340 reason: "off" | "ended" | "used" | "pool" | null;
341};
342
Paid features: a workspace turns on Deployments with a monthly plan343/**
344 * A paid feature a workspace turns on with a monthly plan, as Cloudflare's
345 * Workers for Platforms or Vercel's Pro are bought. Never free: neither
346 * `free` nor the model allowance covers it. Mirrors `Feature` in
347 * `crates/contracts/src/billing.rs`.
348 */
349export type Feature = "deployments";
350
351/** What the Deployments plan includes each month. Mirrors `deployments_allowance`. */
352export const DEPLOYMENTS_ALLOWANCE = {
353 apps: 10,
354 requests: 1_000_000,
355 cpuMs: 3_000_000,
356 /** What Cloudflare charges g1t past that, in millionths of a dollar. */
357 microsPerAppMonth: 20_000,
358 microsPerMillionRequests: 300_000,
359 microsPerMillionCpuMs: 20_000,
Deployments: a preview for every pull request, production on g1t.page360 /** One second of a build's sandbox; builds are charged, not included. */
361 microsPerBuildSecond: 21,
Agents and memory, checks and conflicts, profiles, slug renames, custom domains362 /** Custom domains across the workspace, and what each one past that costs g1t a month. */
363 customDomains: 3,
364 microsPerDomainMonth: 100_000,
Paid features: a workspace turns on Deployments with a monthly plan365} as const;
366
367export type FeaturePlan = {
368 feature: Feature;
369 title: string;
370 /** Charged every month while the plan is on, in cents. */
371 monthlyCents: number;
372 /** What the price includes, one line each. */
373 includes: string[];
374 /** How usage past the allowance is charged. */
375 overage: string;
376};
377
378export type SubscriptionStatus = "active" | "canceling" | "past_due" | "canceled";
379
380export type Subscription = {
381 feature: Feature;
382 status: SubscriptionStatus;
383 /** RFC 3339: when the period paid for ends. */
384 periodEnd: string | null;
385 startedBy: string;
386 startedAt: string;
387};
388
389/** A feature as a workspace sees it. */
390export type FeatureState = {
391 plan: FeaturePlan;
392 subscription: Subscription | null;
393 /** Whether the feature works for the workspace now. */
394 on: boolean;
395};
396
Agents as a team: lifecycle, merge queue, billing and a new shell397export interface BillingApi {
398 status(): Promise<BillingStatus>;
399 /** Members of the workspace only. */
400 account(workspace: string, viewer: Viewer): Promise<Result<BillingAccount>>;
401 /** Newest first. Members of the workspace only. */
402 ledger(workspace: string, viewer: Viewer): Promise<Result<LedgerEntry[]>>;
The statement is a month at a time, a line per kind of charge403 /** A month of the ledger, grouped by `day` (default) or `project`. Members only. */
404 statement(workspace: string, viewer: Viewer, month?: string | null, group?: "day" | "project"): Promise<Result<Statement>>;
405 /** One statement line's entries, 50 at a time; `before` is the last id seen. */
406 statementEntries(
407 workspace: string,
408 viewer: Viewer,
409 filter: { month: string; kind: string; day?: string | null; project?: string | null; before?: string | null },
410 ): Promise<Result<LedgerEntry[]>>;
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request411 /** What the workspace's agents cost since `since`, broken down. Members only. */
412 usage(workspace: string, viewer: Viewer, since: string): Promise<Result<Usage>>;
Agents as a team: lifecycle, merge queue, billing and a new shell413 /**
414 * Starts a card payment for credit and returns the page to send the
415 * person to. Owners only. The payment's id comes back to `returnUrl` as
416 * `session`.
417 */
418 checkout(actor: User, workspace: string, amountCents: number, returnUrl: string): Promise<Result<{ url: string }>>;
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace419 /**
420 * Stripe's hosted billing page for the workspace: card, invoices, billing
421 * email and address. g1t never handles card numbers. Owners only.
422 */
423 billingPortal(actor: User, workspace: string, returnUrl: string): Promise<Result<{ url: string }>>;
Agents as a team: lifecycle, merge queue, billing and a new shell424 /** Credits a payment once the processor says it was made. Safe to repeat. */
425 confirm(workspace: string, viewer: Viewer, session: string): Promise<Result<BillingAccount>>;
426 /**
427 * Whether a workspace may start an agent now, asked before anything is
428 * opened for it. A failure, with the reason to show, when it has no credit.
429 */
430 canStart(workspace: string): Promise<Result<boolean>>;
A free allowance on g1t's models, so anyone can try its agents431 /** A workspace's free allowance on g1t's hosted models; `exempt` are open to them anyway. */
432 trial(workspace: string, exempt: string[]): Promise<Trial>;
Agents as a team: lifecycle, merge queue, billing and a new shell433 /**
434 * Asks whether a workspace may start an agent and opens the run it will be
435 * charged for. Null when billing is off; a failure when there is no credit.
436 */
Paid features: a workspace turns on Deployments with a monthly plan437 /** Every paid feature and the workspace's plan for each. Members only. */
438 features(workspace: string, viewer: Viewer): Promise<Result<FeatureState[]>>;
439 /**
440 * Starts the card page for a feature's monthly plan. Owners only. The
441 * page's id comes back to `returnUrl` as `session`.
442 */
443 subscribe(actor: User, workspace: string, feature: Feature, returnUrl: string): Promise<Result<{ url: string }>>;
444 /** Turns the feature on once the plan is paid for. Safe to repeat. */
445 confirmSubscription(workspace: string, viewer: Viewer, session: string): Promise<Result<FeatureState>>;
446 /** Ends a plan at the end of its period, or (`resume`) takes that back. Owners only. */
447 cancelSubscription(actor: User, workspace: string, feature: Feature, resume?: boolean): Promise<Result<FeatureState>>;
448 /** Whether a feature works for a workspace now; a failure with the reason when not. */
449 hasFeature(workspace: string, feature: Feature): Promise<Result<boolean>>;
450 /**
451 * Usage past a plan's allowance, charged from credit at cost plus the
452 * margin, once per `reference`. False if it was charged before.
453 */
454 chargeFeature(charge: {
455 workspace: string;
456 feature: Feature;
457 costMicros: number;
458 description: string;
459 repo?: string | null;
460 reference: string;
461 }): Promise<Result<boolean>>;
Prices keep themselves current with what g1t pays462 /**
463 * Usage this month to be charged later (app traffic past a plan), so the
464 * workspace's limit counts it now. Replaces the last report.
465 */
466 notePending(workspace: string, source: "deployments", costMicros: number): Promise<boolean>;
467 /** Every metered price and the recent changes. Public. */
468 prices(): Promise<PriceBook>;
Usage limits: unpaid usage can only go so far469 /** A workspace's limit, for its members. */
470 limit(workspace: string, viewer: Viewer): Promise<Result<Limit>>;
471 /** The same, for the services that enforce it. */
472 checkLimit(workspace: string): Promise<Result<Limit>>;
Every sandbox is metered by the second473 /**
Two limits, real invoices, trust that grows by itself, sales signals474 * The owners' own monthly limit, up to what is available; null goes back
475 * to the default, and `useFullLimit` uses everything available. Owners only.
476 */
477 setSpendLimit(actor: User, workspace: string, spendLimitMicros: number | null, useFullLimit?: boolean): Promise<Result<Limit>>;
478 /** The workspace's invoices from g1t, newest first. Members only. */
479 invoices(workspace: string, viewer: Viewer): Promise<Result<WorkspaceInvoice[]>>;
480 /**
Every sandbox is metered by the second481 * How long a sandbox ran for a workspace, reported when it stops. Its
Prices are what g1t pays plus 20%, from the first second482 * cost is recorded and every second is charged, from the first. False if
483 * `reference` was recorded before.
Every sandbox is metered by the second484 */
485 recordSandbox(usage: {
486 workspace: string;
487 seconds: number;
488 description: string;
489 repo?: string | null;
490 reference: string;
491 }): Promise<Result<boolean>>;
Agents as a team: lifecycle, merge queue, billing and a new shell492 startRun(run: {
493 workspace: string;
494 repo: RepoPath;
495 number: number;
496 task: string;
497 model: string;
Integrations: your own model provider, alerts that open issues, tickets agents read498 /** `workspace` when the run uses the workspace's own model provider. */
499 billedTo?: "g1t" | "workspace";
Prices keep themselves current with what g1t pays500 /** The model session's id, so the run can be settled at AI Gateway's price. */
501 session?: string | null;
Agents as a team: lifecycle, merge queue, billing and a new shell502 }): Promise<Result<RunTicket | null>>;
503}
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request504
505
506/** One slice of usage: what it was for, what it cost, how many runs. */
507export type UsageSlice = { key: string; micros: number; runs: number };
508
509/** What a workspace's agents cost over a period. */
510export type Usage = {
511 since: string;
512 /** Charged, including g1t's margin. */
513 spentMicros: number;
Integrations: your own model provider, alerts that open issues, tickets agents read514 /** What g1t's model provider charged, before the margin. */
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request515 costMicros: number;
Integrations: your own model provider, alerts that open issues, tickets agents read516 /** What runs on the workspace's own provider cost there, estimated. Not charged by g1t. */
517 providerMicros: number;
Usage while free is shown at cost; agents get rustfmt and clippy518 /** What the runs used, at cost: g1t's models and the workspace's own provider together. */
519 usedMicros: number;
520 /** g1t charges nothing for now; the slices then measure usage at cost. */
521 free: boolean;
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request522 runs: number;
523 /** Spend per day and task, keyed `YYYY-MM-DD/task`. */
524 byDay: UsageSlice[];
525 byTask: UsageSlice[];
526 byRepo: UsageSlice[];
527 /** Keyed `namespace/name#number`. */
528 byPull: UsageSlice[];
529 byModel: UsageSlice[];
530 /** Credit bought in the period. */
531 addedMicros: number;
532};