g1t/packages/contracts/src/billing.ts

1,177 lines46,714 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.

Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1import type { ComputeKind, Reservation } from "./compute";
Agents as a team: lifecycle, merge queue, billing and a new shell2import type { User, Viewer } from "./identity";
3import type { RepoPath } from "./repos";
4import type { Result } from "./result";
5
6/** Millionths of a US dollar in one dollar: the unit money is held in. */
7export const MICROS_PER_DOLLAR = 1_000_000;
8
9/** Whether workspaces are charged for agents at all, and with real money. */
10export type BillingStatus = {
11 /**
12 * False when no card processor is configured: nothing is charged, and who
13 * may run agents is decided some other way.
14 */
15 enabled: boolean;
16 /** False while the card processor is in its test mode, where cards are not real. */
17 live: boolean;
Free while g1t is being built out; agents can check out their own forks18 /**
19 * True while g1t is being built out: runs are recorded with what they
20 * cost, but nothing is charged and no credit is needed. Not forever.
21 */
22 free?: boolean;
Agents as a team: lifecycle, merge queue, billing and a new shell23};
24
25/** A workspace's standing. */
26export type BillingAccount = {
27 workspace: string;
28 /**
29 * Credit left, in millionths of a dollar. Can dip below zero by the cost
30 * of the runs that were under way when it ran out.
31 */
32 balanceMicros: number;
33 status: BillingStatus;
34 /** What is added to a run's cost, in percent. */
35 marginPercent: number;
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace36 /** The card charged near the limit and when a month closes, if one is saved. */
37 card?: { brand: string; last4: string; expMonth: number; expYear: number } | null;
Agents as a team: lifecycle, merge queue, billing and a new shell38};
39
40/** One line of a workspace's statement. */
41export type LedgerEntry = {
42 id: string;
43 /** Credit bought with a card, or an agent's run. */
44 kind: "top_up" | "usage";
45 /** Positive for credit added, negative for usage. */
46 amountMicros: number;
47 description: string;
48 /** For usage: the repository and pull request the agent worked on. */
49 repo: string | null;
50 number: number | null;
51 /** For usage: `implement`, `review` or `update`. */
52 task: string | null;
53 /** For usage: the model, by its public name. */
54 model: string | null;
Integrations: your own model provider, alerts that open issues, tickets agents read55 /** For usage: who paid the model provider. */
56 billedTo: "g1t" | "workspace";
Agents as a team: lifecycle, merge queue, billing and a new shell57 /** For a top-up: the username of whoever paid. */
58 createdBy: string | null;
59 /** RFC 3339. */
60 createdAt: string;
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace61 /** The workspace the line belongs to, which tells an enterprise's lines apart. */
62 workspace?: string | null;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look63 /** For usage: what the plan's included usage paid of it. `amountMicros` is what is left to pay. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put64 creditMicros?: number;
65 /** For usage: what the workspace's trial credit paid of it. */
66 trialMicros?: number;
67 /** For usage: what g1t's open-source pool paid of it. */
68 ossMicros?: number;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look69 /** For usage: what g1t covered itself, such as a trial's last run past its credit. */
70 givenMicros?: number;
Agents as a team: lifecycle, merge queue, billing and a new shell71};
72
73/** What lets a sandbox, and nothing else, report what its run cost. */
74export type RunTicket = { runId: string; token: string };
75
76/**
77 * What agents cost, charged to the workspace they worked for. A workspace
78 * buys credit; each run deducts its cost plus g1t's margin; with no credit,
79 * no agent starts.
80 */
A free allowance on g1t's models, so anyone can try its agents81/**
82 * The free allowance on g1t's hosted models for a workspace not otherwise
83 * open to them: a few dollars of model cost each, out of one pool, until a
84 * date. Mirrors `Trial` in `crates/contracts/src/billing.rs`.
85 */
Billing accounts, terms and enterprises; g1t is no longer free86/** How an account is charged. Standard unless g1t set otherwise in sudo. */
87export type Terms = {
88 kind: "standard" | "comped" | "custom";
89 discountPercent: number;
90 ceilingMicros: number | null;
91 note: string;
92 until: string | null;
93 setBy: string | null;
94 setAt: string | null;
95};
96
97/**
98 * Who pays: a workspace's own account, or an enterprise's, which pays for
99 * several workspaces with one bill and one limit.
100 */
101export type PayingAccount = {
102 id: string;
103 kind: "workspace" | "enterprise";
104 name: string;
105 terms: Terms;
106 workspaces: string[];
Stripe webhooks, enterprise invoices, and sudo for both107 /** Where an enterprise's invoices go. */
108 billingEmail?: string | null;
109 /** An enterprise's invoices, newest first. */
110 invoices?: EnterpriseInvoice[];
Billing accounts, terms and enterprises; g1t is no longer free111 createdAt: string;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put112 /** What g1t staff set for the account beyond its terms. */
113 allowances?: Allowances;
114};
115
116/** Set per account by g1t staff in sudo, on top of its terms. */
117export type Allowances = {
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look118 /** The g1t plan without its monthly price; usage is charged as usual. Comped accounts have it anyway. */
119 plan: boolean;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put120 /** Each public repository's monthly cap on g1t's open-source pool; null for the default. */
121 ossRepoMicros: number | null;
122 /** Each workspace's trial credit, outside the monthly pool; null for the default. */
123 trialMicros: number | null;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look124 /** Agents at once, in place of the plan's (2 in the first month or on the trial, then 10); null for the default. */
125 maxConcurrentAgents?: number | null;
126 /** One run's spend cap, in place of the owners' and the default $2; null for none. */
127 runCapMicros?: number | null;
128 /** What one issue's agents may spend in all, in place of the owners' and the default $10; null for none. */
129 issueCapMicros?: number | null;
Audit logs are kept by plan: a week on free, 90 days on the plan, and what staff set for an account in sudo130 /** Days of audit log its workspaces keep, in place of the plan's (7 free, 90 on the plan), longer or shorter; null for the plan's. */
131 auditRetentionDays?: number | null;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look132 /** A hold on new compute, with why; null for none. */
133 hold?: string | null;
Billing accounts, terms and enterprises; g1t is no longer free134};
135
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look136// --- Entitlements, and compute started under a reservation ------------------
137//
138// Every service that starts compute asks billing first:
139// 1. `entitlements(workspace)`: what it may do at all, its caps, and whether compute is paused.
140// 2. `reserve(...)`: holds the estimate against what may pay for it, so starts at the same moment
141// cannot overshoot together. Answers who pays first, or refuses with a stable code
142// (`not_paid`, `trial_used`, `limit`, `paused`, `oss_pool_empty`) and a message for the owner.
143// 3. `settle(reservationId, actualMicros)`: releases the hold. The charge goes on the ledger the usual way.
144// A reservation never settled lapses after `RESERVATION_HOURS`.
145
146/** A reservation that is never settled stops holding after this long. */
147export const RESERVATION_HOURS = 3;
148/** What a ceiling reads as when there is none (g1t's own workspaces). */
149export const UNLIMITED_MICROS = 1_000_000_000_000_000;
150
151/** What a workspace pays g1t on, as far as compute is concerned. Mirrors `PlanKind`. */
152export type PlanKind = "free" | "paid" | "internal" | "enterprise";
153
154// `ComputeKind` (what compute is for), `PaidBy` (who pays first: credit, trial, oss, on_demand) and
155// `Reservation` are in `./compute`, with the gate that calls `reserve` and `settle`.
156
157/** One level reached: 50, 75, 90 or 100 percent. */
158export type UsageAlert = {
159 /** `included` (the plan's included usage), `spend_limit` or `ceiling`. */
160 meter: "included" | "spend_limit" | "ceiling" | string;
161 level: number;
162 usedMicros: number;
163 limitMicros: number;
164 message: string;
165};
166
167/** An hour's spend well above the workspace's usual: new compute waits for an owner. */
168export type Spike = {
169 id: string;
170 /** `open` (waiting), `continued` (keep going) or `stopped`. */
171 status: "open" | "continued" | "stopped" | string;
172 hourMicros: number;
173 averageMicros: number;
174 detectedAt: string;
175 decidedBy?: string | null;
176 decidedAt?: string | null;
177 /** While continued: until when, unless spend doubles again first. */
178 until?: string | null;
179};
180
181/** What a workspace may do now. Mirrors `Entitlements` in `crates/contracts/src/billing.rs`. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put182export type Entitlements = {
183 workspace: string;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look184 plan: PlanKind;
185 /** May start sandboxes, models, deployments and semantic search at all: paid, internal, enterprise, or free with trial credit left. */
186 compute: boolean;
187 /** The one-time trial credit left; 0 if none or used. */
188 trialMicrosLeft: number;
189 /** A card check has been done; the trial and the open-source pool need it. */
190 trialVerified: boolean;
191 /** A paid workspace still in its first billing cycle. */
192 firstMonth: boolean;
193 /** 2 in the first month or on the trial, 10 after; staff can override it. */
194 maxConcurrentAgents: number;
195 /** 60 in the first month or on the trial; otherwise the guardrails' own caps. */
196 maxRunMinutes: number;
197 /** One run's spend cap, $2 by default; staff can override it. */
198 runCapMicros: number;
199 /** Agent spend on one issue in all, $10 by default. */
200 issueCapMicros: number;
201 /** g1t's ceiling on usage not yet paid for; `UNLIMITED_MICROS` for g1t's own; 0 for free. */
202 ceilingMicros: number;
203 /** Usage not yet paid for this month, prepayment taken off. */
204 exposureMicros: number;
205 /** Why new compute is paused, for the owner; null when it is not. */
206 paused: string | null;
207 /** What open reservations hold now. */
208 heldMicros?: number;
209 /** Paid in advance and not used yet. */
210 prepaidMicros?: number;
211 /** The plan's included usage each month, and what of it is used. */
212 includedMicros?: number;
213 includedUsedMicros?: number;
Audit logs are kept by plan: a week on free, 90 days on the plan, and what staff set for an account in sudo214 /** How far back the audit log can be read and exported, and what is kept: the plan's days, or what g1t staff set for the account. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put215 auditRetentionDays: number;
Audit logs are kept by plan: a week on free, 90 days on the plan, and what staff set for an account in sudo216 /** Whether `auditRetentionDays` is what staff set for the account rather than the plan's. */
217 auditRetentionCustom?: boolean;
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas218 /** Private repository storage free for every workspace: past it, the plan pays and a free workspace's pushes stop. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put219 freePrivateStorageBytes: number;
220 /** The last daily measure of the workspace's private repositories (a lower bound). */
221 privateStorageBytes: number;
222 /** What g1t's open-source pool paid for the workspace this month. */
223 ossPaidMicros: number;
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas224 /** Deploy build time this month, every second of it metered. */
225 buildSecondsUsed?: number;
226 /** Git operations this month, and how many are free for every workspace. */
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look227 gitOperations?: number;
228 gitOperationsIncluded?: number;
229 /** The smallest amount a card is charged when a month closes. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put230 minChargeMicros: number;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look231 /** A spend spike waiting for an owner, or decided. */
232 spike?: Spike | null;
233 /** Where usage stands against what is included and the limits, from 50%. */
234 alerts?: UsageAlert[];
235};
236
237/** A hold on a start's estimated cost, as billing answers it (`Reservation` in `./compute`, and more). */
238export type ReservationHeld = Reservation & {
239 /** What is held, at cost; may be less than the estimate for a free workspace's last bit of trial. */
240 heldMicros?: number;
241 /** When the hold lapses if never settled. */
242 expiresAt?: string;
243};
244
245/** A request to g1t: a higher limit, or help with usage past what was meant. */
246export type LimitRequest = {
247 id: string;
248 workspace: string;
249 kind: "limit" | "overage" | string;
250 amountMicros: number;
251 reason: string;
252 expectedMonthlyMicros: number;
253 status: "open" | "approved" | "declined" | string;
254 decidedMicros?: number | null;
255 decidedBy?: string | null;
256 /** The answer, as the owner sees it. */
257 answer?: string | null;
258 createdBy: string;
259 createdAt: string;
260 decidedAt?: string | null;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put261};
262
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look263/** What staff see beside a request. */
264export type WorkspaceHistory = {
265 plan: PlanKind | null;
266 months: MonthFigures[];
267 paidClearedMicros: number;
268 payments: number;
269 disputes: number;
270 declines: number;
271 firstSeen: string | null;
272 ceilingMicros: number | null;
273 maxCeilingMicros: number | null;
274 spendLimitMicros: number | null;
275 lastHourMicros: number;
276 averageHourMicros: number;
277 lastDayMicros: number;
278};
279
280export type LimitRequestReview = { request: LimitRequest; history: WorkspaceHistory };
281
282/** What a one-time goodwill credit comes to: the margin on the overage, always, plus its cost up to the cap. */
283export type Goodwill = {
284 overageMicros: number;
285 marginMicros: number;
286 costMicros: number;
287 creditMicros: number;
288 absorbedMicros: number;
289};
290
291/** A workspace whose month went well past its usual, or hit a spike. */
292export type Overage = {
293 workspace: string;
294 plan: PlanKind;
295 typicalMonthMicros: number;
296 thisMonthMicros: number;
297 costMicros: number;
298 marginMicros: number;
299 spike: Spike | null;
300 topEntries: LedgerEntry[];
301 goodwill: Goodwill;
302 goodwillAvailable: boolean;
303 lastGoodwillAt: string | null;
304 request: LimitRequest | null;
305};
306
307/** One workspace's recent pace. */
308export type Velocity = {
309 workspace: string;
310 plan: PlanKind;
311 lastHourMicros: number;
312 averageHourMicros: number;
313 lastDayMicros: number;
314 thisMonthMicros: number;
315 ratio: number;
316 spike: Spike | null;
317 firstSeen: string | null;
318};
319
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put320/** g1t's capped budgets for free usage this month. */
321export type Pools = {
322 month: string;
323 trialGrantedMicros: number;
324 trialPoolMicros: number;
325 trialGrants: number;
326 ossUsedMicros: number;
327 ossPoolMicros: number;
328 ossRepoMicros: number;
329};
330
Billing accounts, terms and enterprises; g1t is no longer free331export type AccountSummary = {
332 account: PayingAccount;
333 limit: Limit;
334 chargedMicros: number;
335 costMicros: number;
336 paidMicros: number;
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace337 /** The same figures for each of the account's workspaces that has any. */
338 byWorkspace: WorkspaceFigures[];
Two limits, real invoices, trust that grows by itself, sales signals339 /** The last six months, oldest first. */
340 months?: MonthFigures[];
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace341};
342
343/** One workspace's share of an `AccountSummary`. */
344export type WorkspaceFigures = { workspace: string; chargedMicros: number; costMicros: number; paidMicros: number };
345
Stripe webhooks, enterprise invoices, and sudo for both346export type StripeStatus = {
347 /** `test` or `live`, from the key; `off` without one. */
348 mode: "test" | "live" | "off" | string;
Stripe's webhook secret is a Worker secret, STRIPE_WEBHOOK_SECRET, from a destination made in Stripe's dashboard349 /** Whether `STRIPE_WEBHOOK_SECRET` is set, so events can be checked. */
350 secretSet: boolean;
351 /** The destination at billing's address in Stripe, as Stripe has it. */
352 webhook: { url: string; endpointId: string; status: "enabled" | "disabled" | string; events: string[]; createdAt: string } | null;
353 /** Events billing handles that the destination does not send. */
354 missingEvents: string[];
Stripe webhooks, enterprise invoices, and sudo for both355 recentEvents: { id: string; kind: string; outcome: string; receivedAt: string }[];
356 error: string | null;
357};
358
359/** An enterprise's invoice: one line per workspace, paid on Stripe's page. */
360export type EnterpriseInvoice = {
361 invoiceId: string;
362 hostedUrl: string | null;
363 amountMicros: number;
364 status: "open" | "paid" | "overdue" | "void" | string;
365 period: string;
366 lines: { workspace: string; amountMicros: number }[];
367 createdAt: string;
368};
369
Two limits, real invoices, trust that grows by itself, sales signals370/** A workspace's invoice: monthly, or when charged near its limit. Itemised, in Stripe's billing page. */
371export type WorkspaceInvoice = {
372 invoiceId: string;
373 workspace: string;
374 reason: "month" | "threshold" | string;
375 period: string;
376 amountMicros: number;
377 status: "paid" | "open" | "failed" | "void" | string;
378 hostedUrl: string | null;
379 pdfUrl: string | null;
380 lines: { description: string; amountMicros: number }[];
381 createdAt: string;
382};
383
The statement is a month at a time, a line per kind of charge384/** A month of the ledger, grouped by day or project, a line per kind of charge. */
385export type Statement = {
386 month: string;
387 months: string[];
388 groups: {
389 key: string;
390 label: string;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look391 /** `coveredMicros`: what the plan's included usage, the trial, the open-source pool or g1t paid, not in `chargedMicros`. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put392 lines: { kind: string; count: number; chargedMicros: number; costMicros: number; coveredMicros?: number }[];
The statement is a month at a time, a line per kind of charge393 chargedMicros: number;
394 }[];
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put395 totals: {
396 chargedMicros: number;
397 paidMicros: number;
398 costMicros: number;
399 entries: number;
400 /** What paid for usage before it was charged, such as "Paid by g1t's open-source pool". */
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look401 covered?: { source: "included" | "trial" | "oss_pool" | "given" | string; label: string; micros: number }[];
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put402 /** Owed when the month closed but under the minimum charge: on the next invoice. */
403 carriedMicros?: number;
404 };
The statement is a month at a time, a line per kind of charge405};
406
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look407export type MonthFigures = {
408 month: string;
409 /** Usage charged, after what paid for it first. */
410 chargedMicros: number;
411 /** What usage cost g1t: never a workspace's own model provider. */
412 costMicros: number;
413 paidMicros: number;
414 /** The plan's monthly price, paid. */
415 plansMicros?: number;
416 /** What g1t gave at price (internal use, trials, the open-source pool, goodwill, covered). Not margin. */
417 givenMicros?: number;
418};
419
420/** What g1t gave this month from one source. */
421export type GivenFigures = { source: "internal" | "trial" | "oss_pool" | "goodwill" | "covered" | string; label: string; micros: number; costMicros: number };
422
423/** One internal workspace's use this month, and why it is not charged. */
424export type InternalUse = { workspace: string; reason: string; costMicros: number; entries: number };
Two limits, real invoices, trust that grows by itself, sales signals425
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily426export type SignalKind = "at_limit" | "near_ceiling" | "declined" | "growing" | "established" | "first_payment" | "high_spend" | "cost_over_revenue";
Two limits, real invoices, trust that grows by itself, sales signals427
428/** Why a workspace is worth reaching out to. */
429export type Signal = {
430 workspace: string;
431 kind: SignalKind;
432 detail: string;
433 valueMicros: number;
434 stage: string | null;
435 owner: string | null;
Billing lists every invoice and every staff change; signals carry follow-ups436 nextStep?: string | null;
437 /** When the next step is due, YYYY-MM-DD. */
438 nextAt?: string | null;
439};
440
441/** One invoice g1t has sent, a workspace's or an enterprise's. */
442export type InvoiceSummary = {
443 invoiceId: string;
444 kind: "workspace" | "enterprise";
445 account: string;
446 name: string;
447 reason: string;
448 period: string;
449 amountMicros: number;
450 status: string;
451 hostedUrl: string | null;
452 createdAt: string;
453 paidAt: string | null;
Two limits, real invoices, trust that grows by itself, sales signals454};
455
456export type SalesStage = "none" | "lead" | "contacted" | "negotiating" | "won" | "lost" | "churn_risk";
457
458export type SalesRecord = {
459 workspace: string;
460 stage: SalesStage | string;
461 owner: string | null;
462 nextStep: string | null;
463 nextAt: string | null;
464 notes: { id: string; text: string; by: string; createdAt: string }[];
465 updatedAt: string | null;
466};
467
468export type Overview = {
469 month: string;
470 months: MonthFigures[];
471 byKind: { kind: string; chargedMicros: number; costMicros: number }[];
472 payingWorkspaces: number;
473 stopped: number;
474 nearCeiling: number;
475 declined: number;
476 openInvoicesMicros: number;
477 followUpsDue: number;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put478 /** g1t's capped budgets for free usage, this month. */
479 pools?: Pools | null;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look480 /** Usage charged plus the plan's price paid, this month. */
481 revenueMicros?: number;
482 activePlans?: number;
483 planMrrMicros?: number;
484 /** What g1t gave this month, by source, apart from its margin. */
485 given?: GivenFigures[];
486 /** g1t's own and Flagon's workspaces: what their use cost, and why they are not charged. */
487 internal?: InternalUse[];
488 openRequests?: number;
489 overages?: number;
490 openSpikes?: number;
Two limits, real invoices, trust that grows by itself, sales signals491};
492
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace493/** A customer's Stripe billing page, for staff to send them. */
494export type BillingLink = {
495 /** One-time and short-lived, signed in already. */
496 portalUrl: string;
497 /** The page's sign-in, which does not expire: the customer signs in by email. */
498 loginUrl: string | null;
499 customerEmail: string | null;
500 expiresNote: string;
Billing accounts, terms and enterprises; g1t is no longer free501};
502
503export type AdminAction = { id: string; account: string; action: string; detail: string; by: string; createdAt: string };
504
505export type AccountDetail = {
506 summary: AccountSummary;
507 workspaces: Limit[];
508 ledger: LedgerEntry[];
509 audit: AdminAction[];
510};
511
512/** Staff-only billing, for sudo.g1t.sh. Every change names who made it. */
513export interface BillingAdminApi {
514 accounts(query?: string): Promise<AccountSummary[]>;
515 account(id: string): Promise<Result<AccountDetail>>;
516 setTerms(id: string, terms: Terms, by: string): Promise<Result<PayingAccount>>;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put517 /** Team on or off without charge, and the account's share of the pools. Needs a note. */
518 setAllowances(id: string, allowances: Allowances, note: string, by: string): Promise<Result<PayingAccount>>;
Billing accounts, terms and enterprises; g1t is no longer free519 createEnterprise(name: string, workspaces: string[], by: string): Promise<Result<PayingAccount>>;
520 attach(workspace: string, account: string | null, by: string): Promise<Result<PayingAccount>>;
521 credit(workspace: string, amountMicros: number, note: string, by: string): Promise<Result<LedgerEntry>>;
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace522 /** The workspace's Stripe billing page, to send to the customer. Logged. */
523 billingLink(workspace: string, by: string): Promise<Result<BillingLink>>;
Stripe webhooks, enterprise invoices, and sudo for both524 /** Where billing stands with Stripe; with `setup`, registers the webhook first. */
Stripe's webhook secret is a Worker secret, STRIPE_WEBHOOK_SECRET, from a destination made in Stripe's dashboard525 /** Stripe's state for billing; `fix` enables the destination and adds missing events first. */
526 stripe(fix?: boolean, by?: string): Promise<StripeStatus>;
Stripe webhooks, enterprise invoices, and sudo for both527 /** Where an enterprise's invoices go; makes its Stripe customer. */
528 enterpriseBilling(id: string, email: string, by: string): Promise<Result<PayingAccount>>;
529 /** Sends an enterprise its invoice now, for what its workspaces owe. */
530 invoiceEnterprise(id: string, by: string): Promise<Result<EnterpriseInvoice>>;
531 /** Exactly these workspaces' accounts, such as one page of the list. */
532 accountsFor(workspaces: string[]): Promise<AccountSummary[]>;
Two limits, real invoices, trust that grows by itself, sales signals533 /** Every workspace worth reaching out to, most urgent first. */
534 signals(): Promise<Signal[]>;
535 /** The business at a glance. */
536 overview(): Promise<Overview>;
537 /** A workspace's sales record. */
538 sales(workspace: string): Promise<SalesRecord>;
539 setSales(workspace: string, record: { stage: string; owner?: string | null; nextStep?: string | null; nextAt?: string | null }, by: string): Promise<Result<SalesRecord>>;
540 addNote(workspace: string, text: string, by: string): Promise<Result<SalesRecord>>;
541 /** A workspace's invoices from g1t, for staff. */
542 workspaceInvoices(workspace: string): Promise<WorkspaceInvoice[]>;
Billing lists every invoice and every staff change; signals carry follow-ups543 /** Every invoice g1t has sent, newest first. */
544 allInvoices(filter?: { status?: string; month?: string }): Promise<InvoiceSummary[]>;
545 /** Every change made in sudo and by Stripe, newest first, 100 at a time. */
546 audit(filter?: { by?: string; action?: string; before?: string }): Promise<AdminAction[]>;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look547 /** Limit and overage requests, with each workspace's history; `open` by default. */
548 limitRequests(status?: "open" | "approved" | "declined" | "all"): Promise<LimitRequestReview[]>;
549 /** Approve (at the amount asked, or another) or decline; the owner is told in the app and by email. */
550 decideLimitRequest(id: string, decision: "approve" | "decline", amountMicros: number | null, note: string, by: string): Promise<Result<LimitRequest>>;
551 /** The Overages queue. */
552 overages(): Promise<Overage[]>;
553 /** A goodwill credit; no amount is the one-click credit. Larger, or a second in 12 months, needs a reason. */
554 goodwill(workspace: string, amountMicros: number | null, reason: string, by: string, day?: string | null): Promise<Result<LedgerEntry>>;
555 /** Workspaces spending in the last day, fastest first. */
556 velocity(): Promise<Velocity[]>;
557 /** Money that reached g1t outside the card pages, such as a bank transfer: entered as a payment. */
558 recordPayment(workspace: string, amountMicros: number, reference: string, note: string, by: string): Promise<Result<LedgerEntry>>;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily559 /** Costs & margin: Cloudflare's bill against what g1t charged, over the last `days` (7 to 90, 30 by default). */
560 costs(days?: number): Promise<CostsReport>;
561 /** The open margin alerts, for the banner on every page. */
562 costAlerts(): Promise<MarginAlert[]>;
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays563 /** g1t's own spend against its caps: the daily breaker and comped budgets. */
564 spendCaps(): Promise<SpendCaps>;
565 /** Lets hosted-model runs start again for the rest of today (UTC); needs a note. */
566 liftBreaker(note: string, by: string): Promise<Result<SpendCaps>>;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily567 /** Approve or reject a price proposal; a rejection needs a note. An approved rise waits out the notice period. */
568 decideProposal(id: string, decision: "approve" | "reject", note: string, by: string): Promise<Result<PriceProposal>>;
569 setCostSettings(settings: CostSettings, by: string): Promise<Result<CostSettings>>;
570 setCostMapping(mapping: CostMappingInput, by: string): Promise<Result<CostMapping>>;
571 /** Reads Cloudflare's bill and reconciles now, as the daily run does. */
572 runCosts(by: string): Promise<Result<CostsRun>>;
Billing accounts, terms and enterprises; g1t is no longer free573}
574
Usage limits: unpaid usage can only go so far575/** How much a workspace has earned g1t's trust with money. */
Two limits, real invoices, trust that grows by itself, sales signals576export type Trust = "new" | "paid" | "established" | "reviewed" | "internal";
Usage limits: unpaid usage can only go so far577
578/**
579 * How far a workspace's unpaid usage has gone this month, and where its
580 * work stops: past `ceilingMicros`, no new sandboxes, builds or app
581 * requests. Usage counts at its cost to g1t or its charge, whichever is
582 * more, so it counts while g1t is free too.
583 */
584export type Limit = {
585 workspace: string;
Billing accounts, terms and enterprises; g1t is no longer free586 /** The account that pays: the workspace's own (`ws_<slug>`), or its enterprise's. */
587 account: string;
588 accountName: string;
Usage limits: unpaid usage can only go so far589 trust: Trust;
590 exposureMicros: number;
591 /** The lower of g1t's ceiling and the owner's spend limit; null for g1t's own. */
592 ceilingMicros: number | null;
593 trustCeilingMicros: number | null;
594 spendLimitMicros: number | null;
595 state: "ok" | "warning" | "stopped";
596 message: string | null;
Two limits, real invoices, trust that grows by itself, sales signals597 /** Charged this month: what the spend limit is measured against. */
598 spentMicros?: number;
599 /** True while the owners have not chosen a limit, so the automatic one applies: $200, or twice last month's spend. */
600 defaultSpendLimit?: boolean;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look601 /** The most owners may set their own limit to without asking: the highest ceiling ever, plus what is prepaid. */
Two limits, real invoices, trust that grows by itself, sales signals602 availableMicros?: number | null;
603 /** How the ceiling grows from here, in a sentence. */
604 growth?: string | null;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look605 /** Paid in advance and not used yet; raises what can be used before work stops by as much. */
606 prepaidMicros?: number;
607 /** The highest ceiling the workspace has had. */
608 maxCeilingMicros?: number | null;
609 /** The most owners may raise the limit to themselves, once: twice the highest ceiling. Null once used. */
610 raiseOnceMicros?: number | null;
611 /** When the one-time raise was used. */
612 raisedAt?: string | null;
613 /** A paid workspace's first billing cycle, on the starting ceiling. */
614 firstMonth?: boolean;
Usage limits: unpaid usage can only go so far615};
616
Prices keep themselves current with what g1t pays617/** One metered unit: what it costs g1t and what it is sold at; the price follows the cost. */
618export type Price = {
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put619 meter:
620 | "sandbox_second"
621 | "build_second"
622 | "app_requests"
623 | "app_cpu"
624 | "app_month"
625 | "custom_domain_month"
626 | "private_storage"
627 | "embedding_tokens"
628 | "scan_cpu"
629 | "scan_rows"
630 | string;
Prices keep themselves current with what g1t pays631 title: string;
632 unit: string;
633 costMicros: number;
634 markupPercent: number;
635 priceMicros: number;
636 /** `list`: Cloudflare's published price. `cloudflare`: measured from Cloudflare's bill. */
637 source: "list" | "cloudflare" | string;
638 checkedAt: string | null;
639 updatedAt: string;
640};
641
642export type PriceChange = {
643 meter: string;
644 oldCostMicros: number;
645 newCostMicros: number;
646 markupPercent: number;
Prices are what g1t pays plus 20%, from the first second647 /** The markup before, when the change was to the markup rather than the cost. */
648 oldMarkupPercent?: number;
Prices keep themselves current with what g1t pays649 reason: string;
650 createdAt: string;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily651 /** When a change still to come takes effect: a rise is announced before it is charged. */
652 effectiveAt?: string;
Prices keep themselves current with what g1t pays653};
654
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put655export type PriceBook = {
656 prices: Price[];
657 changes: PriceChange[];
658 modelMarginPercent: number;
659 /** Every plan, as sold now. */
660 plans?: FeaturePlan[];
661 /** What is free, and the capped budgets that pay for it. */
662 free?: FreeTier | null;
663};
Prices keep themselves current with what g1t pays664
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas665/** One kind of meter's usage this month, from `usage_meters`. */
666export type MeterUsage = {
667 /** `agents`, `builds`, `requests`, `domains`, `git_storage` or `search_scans`. */
668 key: string;
669 label: string;
670 /** At price (cost plus 20%, on the account's terms), before what paid for it. */
671 micros: number;
672 /** How much, when it is known: `12 runs`, `41 build minutes`. */
673 quantity?: string | null;
674};
675
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put676/** What g1t gives without a plan; each is paid for by a capped budget. */
677export type FreeTier = {
678 /** Each new workspace's trial credit, once. */
679 trialWorkspaceMicros: number;
680 /** Trial grants each month, in all; new trials wait when it is spent. */
681 trialMonthlyPoolMicros: number;
682 /** g1t's open-source pool each month, and any one repository's share. */
683 ossPoolMicros: number;
684 ossRepoMicros: number;
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas685 /** Private repository storage free for every workspace. Past it, the plan pays; a free workspace's pushes stop. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put686 freePrivateStorageBytes: number;
Audit logs are kept by plan: a week on free, 90 days on the plan, and what staff set for an account in sudo687 /** Days of audit log a free workspace keeps. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put688 auditRetentionDays: number;
Audit logs are kept by plan: a week on free, 90 days on the plan, and what staff set for an account in sudo689 /** Days of audit log the g1t plan keeps, and g1t's own and enterprise workspaces; longer by arrangement. */
690 planAuditRetentionDays?: number;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look691 /** The smallest amount a card is charged when a month closes; less carries over. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put692 minChargeMicros: number;
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas693 /** Git operations free for every workspace each month. Past it, the plan pays; a free workspace is slowed down. */
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look694 gitOperationsIncluded?: number;
695 /** A new paid workspace's ceiling in its first month. */
696 paidStartCeilingMicros?: number;
697 /** The most a one-click goodwill credit can cost g1t. */
698 overageForgiveCostMicros?: number;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put699};
700
701/**
702 * A workspace's trial credit: one grant per workspace, made the first time
703 * it uses something, out of a pool that resets each calendar month. Mirrors
704 * `Trial` in `crates/contracts/src/billing.rs`.
705 */
A free allowance on g1t's models, so anyone can try its agents706export type Trial = {
707 open: boolean;
708 usedMicros: number;
709 limitMicros: number;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put710 /** No longer used: trials do not end on a date. */
A free allowance on g1t's models, so anyone can try its agents711 endsAt: string | null;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put712 /** Why it is closed: `off`, `used` (this workspace's grant is spent) or `pool` (this month's are given out). */
A free allowance on g1t's models, so anyone can try its agents713 reason: "off" | "ended" | "used" | "pool" | null;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put714 /** Whether the workspace has its grant already. */
715 granted?: boolean;
716 /** With `pool`: when new trials start again, the first of next month. */
717 waitsUntil?: string | null;
A free allowance on g1t's models, so anyone can try its agents718};
719
Paid features: a workspace turns on Deployments with a monthly plan720/**
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look721 * What a workspace pays a monthly price for: the g1t plan (`plan`). Deployments
722 * are part of it; `has_feature` for `deployments` answers whether the workspace
723 * has the plan. Mirrors `Feature` in `crates/contracts/src/billing.rs`.
Paid features: a workspace turns on Deployments with a monthly plan724 */
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look725export type Feature = "plan" | "deployments";
Paid features: a workspace turns on Deployments with a monthly plan726
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas727/**
728 * What deployments cost g1t, in millionths of a dollar: fallbacks for when
729 * billing's price book cannot be read. Not an allowance: on the plan every
730 * unit is metered from the first, at cost plus 20%, and drawn from the
731 * plan's included usage first. Projects, previews and the apps behind them
732 * are not metered at all. Mirrors `deployment_costs`.
733 */
734export const DEPLOYMENT_COSTS = {
Paid features: a workspace turns on Deployments with a monthly plan735 microsPerMillionRequests: 300_000,
736 microsPerMillionCpuMs: 20_000,
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas737 /** One second of a build's sandbox: a fallback; billing charges the price book's `build_second`. */
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look738 microsPerBuildSecond: 15,
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas739 /** One custom domain for a month. */
Agents and memory, checks and conflicts, profiles, slug renames, custom domains740 microsPerDomainMonth: 100_000,
Paid features: a workspace turns on Deployments with a monthly plan741} as const;
742
743export type FeaturePlan = {
744 feature: Feature;
745 title: string;
746 /** Charged every month while the plan is on, in cents. */
747 monthlyCents: number;
748 /** What the price includes, one line each. */
749 includes: string[];
750 /** How usage past the allowance is charged. */
751 overage: string;
752};
753
754export type SubscriptionStatus = "active" | "canceling" | "past_due" | "canceled";
755
756export type Subscription = {
757 feature: Feature;
758 status: SubscriptionStatus;
759 /** RFC 3339: when the period paid for ends. */
760 periodEnd: string | null;
761 startedBy: string;
762 startedAt: string;
763};
764
765/** A feature as a workspace sees it. */
766export type FeatureState = {
767 plan: FeaturePlan;
768 subscription: Subscription | null;
769 /** Whether the feature works for the workspace now. */
770 on: boolean;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put771 /** On without a plan: comped terms, or given by g1t. Nothing to pay or turn off. */
772 included?: boolean;
Paid features: a workspace turns on Deployments with a monthly plan773};
774
Agents as a team: lifecycle, merge queue, billing and a new shell775export interface BillingApi {
776 status(): Promise<BillingStatus>;
777 /** Members of the workspace only. */
778 account(workspace: string, viewer: Viewer): Promise<Result<BillingAccount>>;
779 /** Newest first. Members of the workspace only. */
780 ledger(workspace: string, viewer: Viewer): Promise<Result<LedgerEntry[]>>;
The statement is a month at a time, a line per kind of charge781 /** A month of the ledger, grouped by `day` (default) or `project`. Members only. */
782 statement(workspace: string, viewer: Viewer, month?: string | null, group?: "day" | "project"): Promise<Result<Statement>>;
783 /** One statement line's entries, 50 at a time; `before` is the last id seen. */
784 statementEntries(
785 workspace: string,
786 viewer: Viewer,
787 filter: { month: string; kind: string; day?: string | null; project?: string | null; before?: string | null },
788 ): Promise<Result<LedgerEntry[]>>;
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request789 /** What the workspace's agents cost since `since`, broken down. Members only. */
790 usage(workspace: string, viewer: Viewer, since: string): Promise<Result<Usage>>;
Agents as a team: lifecycle, merge queue, billing and a new shell791 /**
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look792 * Prepays usage ($25 at least) and returns the page to send the person to:
793 * by card with 3-D Secure, or by bank transfer from $1,000. Owners only.
794 * The payment's id comes back to `returnUrl` as `session`.
Agents as a team: lifecycle, merge queue, billing and a new shell795 */
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look796 checkout(
797 actor: User,
798 workspace: string,
799 amountCents: number,
800 returnUrl: string,
801 method?: "card" | "bank_transfer",
802 ): Promise<Result<{ url: string }>>;
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace803 /**
804 * Stripe's hosted billing page for the workspace: card, invoices, billing
805 * email and address. g1t never handles card numbers. Owners only.
806 */
807 billingPortal(actor: User, workspace: string, returnUrl: string): Promise<Result<{ url: string }>>;
Agents as a team: lifecycle, merge queue, billing and a new shell808 /** Credits a payment once the processor says it was made. Safe to repeat. */
809 confirm(workspace: string, viewer: Viewer, session: string): Promise<Result<BillingAccount>>;
810 /**
811 * Whether a workspace may start an agent now, asked before anything is
812 * opened for it. A failure, with the reason to show, when it has no credit.
813 */
814 canStart(workspace: string): Promise<Result<boolean>>;
A free allowance on g1t's models, so anyone can try its agents815 /** A workspace's free allowance on g1t's hosted models; `exempt` are open to them anyway. */
816 trial(workspace: string, exempt: string[]): Promise<Trial>;
Agents as a team: lifecycle, merge queue, billing and a new shell817 /**
818 * Asks whether a workspace may start an agent and opens the run it will be
819 * charged for. Null when billing is off; a failure when there is no credit.
820 */
Paid features: a workspace turns on Deployments with a monthly plan821 /** Every paid feature and the workspace's plan for each. Members only. */
822 features(workspace: string, viewer: Viewer): Promise<Result<FeatureState[]>>;
823 /**
824 * Starts the card page for a feature's monthly plan. Owners only. The
825 * page's id comes back to `returnUrl` as `session`.
826 */
827 subscribe(actor: User, workspace: string, feature: Feature, returnUrl: string): Promise<Result<{ url: string }>>;
828 /** Turns the feature on once the plan is paid for. Safe to repeat. */
829 confirmSubscription(workspace: string, viewer: Viewer, session: string): Promise<Result<FeatureState>>;
830 /** Ends a plan at the end of its period, or (`resume`) takes that back. Owners only. */
831 cancelSubscription(actor: User, workspace: string, feature: Feature, resume?: boolean): Promise<Result<FeatureState>>;
832 /** Whether a feature works for a workspace now; a failure with the reason when not. */
833 hasFeature(workspace: string, feature: Feature): Promise<Result<boolean>>;
834 /**
835 * Usage past a plan's allowance, charged from credit at cost plus the
836 * margin, once per `reference`. False if it was charged before.
837 */
838 chargeFeature(charge: {
839 workspace: string;
840 feature: Feature;
841 costMicros: number;
842 description: string;
843 repo?: string | null;
844 reference: string;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put845 /** For a build: how long it ran, so the plan's included build time pays for what it can. */
846 buildSeconds?: number | null;
Paid features: a workspace turns on Deployments with a monthly plan847 }): Promise<Result<boolean>>;
Prices keep themselves current with what g1t pays848 /**
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put849 * What a source cost g1t so far this month, so the workspace's limit
850 * counts it now. Replaces the last report. Billing charges `context`
851 * and `security` itself once the month is over; `deployments` charges
852 * its own.
Prices keep themselves current with what g1t pays853 */
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas854 notePending(
855 workspace: string,
856 source: "deployments" | "domains" | "context" | "security",
857 costMicros: number,
858 /** How much of it, for the Billing page: `1.2 million requests and 3.4 million CPU ms`. */
859 detail?: string | null,
860 ): Promise<boolean>;
861 /**
862 * This month's usage, one line per kind of meter, at what it is charged
863 * before the plan's included usage or a pool paid for it. Members only.
864 */
865 usageMeters(workspace: string, viewer: Viewer): Promise<Result<MeterUsage[]>>;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look866 /** What the workspace may do now: its plan, caps, pause, trial, and what the plan gives it. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put867 entitlements(workspace: string): Promise<Entitlements>;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look868 /**
869 * Holds a start's estimated cost before the work starts. A failure's code says why not:
870 * `paused`, `limit`, `not_paid`, `trial_used` or `oss_pool_empty`, with a message for the owner.
871 */
872 reserve(reservation: {
873 workspace: string;
874 repo: RepoPath;
875 public: boolean;
876 kind: ComputeKind;
877 /** The most the work is expected to cost g1t, before the margin. */
878 estimateMicros: number;
879 }): Promise<Result<ReservationHeld>>;
880 /** Releases a reservation's hold with what the work cost g1t, before the margin. Safe to repeat. */
881 settle(reservationId: string, actualMicros: number): Promise<Result<boolean>>;
882 /** Stripe's page to save and verify a card (3-D Secure, never charged). Owners only. */
883 cardCheck(actor: User, workspace: string, returnUrl: string): Promise<Result<{ url: string }>>;
884 /** Records the card check once Stripe says it passed, and grants the trial if it can. Safe to repeat. */
885 confirmCardCheck(workspace: string, viewer: Viewer, session: string): Promise<Result<Entitlements>>;
886 /** An owner asks for a higher limit, or for help with usage past what was meant. */
887 requestLimit(
888 actor: User,
889 workspace: string,
890 request: { kind: "limit" | "overage"; amountMicros: number; reason: string; expectedMonthlyMicros: number },
891 ): Promise<Result<LimitRequest>>;
892 /** The workspace's requests and their answers, newest first. Members only. */
893 limitRequests(workspace: string, viewer: Viewer): Promise<Result<LimitRequest[]>>;
894 /**
895 * The owners' own caps on agents: one run's spend ($0.10 to $100) and one issue's ($1 to $1,000).
896 * Null goes back to the default ($2 and $10). A cap staff set wins. Owners only.
897 */
898 setCaps(actor: User, workspace: string, caps: { runCapMicros: number | null; issueCapMicros: number | null }): Promise<Result<Entitlements>>;
899 /** An owner's answer to a spend spike: keep going for 24 hours, or stop. */
900 confirmSpike(actor: User, workspace: string, keepGoing: boolean): Promise<Result<Entitlements>>;
Prices keep themselves current with what g1t pays901 /** Every metered price and the recent changes. Public. */
902 prices(): Promise<PriceBook>;
Usage limits: unpaid usage can only go so far903 /** A workspace's limit, for its members. */
904 limit(workspace: string, viewer: Viewer): Promise<Result<Limit>>;
905 /** The same, for the services that enforce it. */
906 checkLimit(workspace: string): Promise<Result<Limit>>;
Every sandbox is metered by the second907 /**
Two limits, real invoices, trust that grows by itself, sales signals908 * The owners' own monthly limit, up to what is available; null goes back
909 * to the default, and `useFullLimit` uses everything available. Owners only.
910 */
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look911 setSpendLimit(
912 actor: User,
913 workspace: string,
914 spendLimitMicros: number | null,
915 useFullLimit?: boolean,
916 /** Use the one-time raise: up to twice the highest ceiling, once per workspace. */
917 raiseOnce?: boolean,
918 ): Promise<Result<Limit>>;
Two limits, real invoices, trust that grows by itself, sales signals919 /** The workspace's invoices from g1t, newest first. Members only. */
920 invoices(workspace: string, viewer: Viewer): Promise<Result<WorkspaceInvoice[]>>;
921 /**
Every sandbox is metered by the second922 * How long a sandbox ran for a workspace, reported when it stops. Its
Prices are what g1t pays plus 20%, from the first second923 * cost is recorded and every second is charged, from the first. False if
924 * `reference` was recorded before.
Every sandbox is metered by the second925 */
926 recordSandbox(usage: {
927 workspace: string;
928 seconds: number;
929 description: string;
930 repo?: string | null;
931 reference: string;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look932 /** What ran; checks, workflows and the merge queue on public repositories may use the open-source pool. */
933 kind?: ComputeKind | null;
934 /** vCPU-seconds used, when the sandbox can tell: the run is priced on its own CPU. */
935 cpuSeconds?: number | null;
936 /** The reservation it started under, settled with this cost. */
937 reservationId?: string | null;
Fast pages, required checks on the branch, self-hosted runners, honest incidents938 /** It ran on one of the workspace's self-hosted runners: its minutes go on usage at $0. */
939 selfHosted?: boolean;
940 /** The machine it ran on, by label (`g1t-4core`); absent, the standard one. */
941 instance?: string | null;
Every sandbox is metered by the second942 }): Promise<Result<boolean>>;
Agents as a team: lifecycle, merge queue, billing and a new shell943 startRun(run: {
944 workspace: string;
945 repo: RepoPath;
946 number: number;
947 task: string;
948 model: string;
Integrations: your own model provider, alerts that open issues, tickets agents read949 /** `workspace` when the run uses the workspace's own model provider. */
950 billedTo?: "g1t" | "workspace";
Prices keep themselves current with what g1t pays951 /** The model session's id, so the run can be settled at AI Gateway's price. */
952 session?: string | null;
Auto model routing: the cheapest tier that can do each piece of work, a retry goes up a tier, and each run records its tier953 /** `small` or `large`: the tier g1t routed the run to, on its hosted models. */
954 tier?: "small" | "large" | null;
Agents as a team: lifecycle, merge queue, billing and a new shell955 }): Promise<Result<RunTicket | null>>;
956}
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request957
958
959/** One slice of usage: what it was for, what it cost, how many runs. */
960export type UsageSlice = { key: string; micros: number; runs: number };
961
962/** What a workspace's agents cost over a period. */
963export type Usage = {
964 since: string;
965 /** Charged, including g1t's margin. */
966 spentMicros: number;
Integrations: your own model provider, alerts that open issues, tickets agents read967 /** What g1t's model provider charged, before the margin. */
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request968 costMicros: number;
Integrations: your own model provider, alerts that open issues, tickets agents read969 /** What runs on the workspace's own provider cost there, estimated. Not charged by g1t. */
970 providerMicros: number;
Usage while free is shown at cost; agents get rustfmt and clippy971 /** What the runs used, at cost: g1t's models and the workspace's own provider together. */
972 usedMicros: number;
973 /** g1t charges nothing for now; the slices then measure usage at cost. */
974 free: boolean;
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request975 runs: number;
976 /** Spend per day and task, keyed `YYYY-MM-DD/task`. */
977 byDay: UsageSlice[];
978 byTask: UsageSlice[];
979 byRepo: UsageSlice[];
980 /** Keyed `namespace/name#number`. */
981 byPull: UsageSlice[];
982 byModel: UsageSlice[];
983 /** Credit bought in the period. */
984 addedMicros: number;
985};
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily986
987/** One of g1t's products (a "bucket") on one day. Money in micros. */
988export type CostDay = { day: string; bucket: string; cfCostMicros: number; ownCostMicros: number; valueMicros: number; cashMicros: number };
989
990/** One product over the range: what customers were charged at price against what it cost. */
991export type ProductMargin = {
992 bucket: string;
993 title: string;
994 /** Cloudflare's bill, or g1t's own figure where Cloudflare does not bill it (`costSource`). */
995 costMicros: number;
996 cfCostMicros: number;
997 ownCostMicros: number;
998 valueMicros: number;
999 marginMicros: number;
1000 marginPercent: number | null;
1001 costSource: "cloudflare" | "ledger" | string;
1002 /** Running g1t, paid for by the plan. */
1003 overhead: boolean;
1004};
1005
1006/** All of g1t: money in (usage and the plan) against every cost. */
1007export type OverallMargin = { usageMicros: number; plansMicros: number; costMicros: number; marginMicros: number; marginPercent: number | null };
1008
1009/** A count, cost or leak that does not add up. */
1010export type CostDrift = {
1011 bucket: string;
1012 title: string;
1013 kind: "count" | "cost" | "leak" | string;
1014 ours: number;
1015 cloudflare: number;
1016 deltaPercent: number | null;
1017 detail: string;
1018 foundAt: string;
1019};
1020
1021export type MarginAlert = {
1022 id: string;
1023 kind: "margin" | "overall" | "leak" | "drift" | "workspace" | string;
1024 /** The product, or the workspace. */
1025 subject: string;
1026 detail: string;
1027 since: string;
1028 openedAt: string;
1029 emailedAt: string | null;
1030};
1031
1032/** A change to a price, measured from what Cloudflare charged. */
1033export type PriceProposal = {
1034 id: string;
1035 meter: string;
1036 title: string;
1037 unit: string;
1038 currentCostMicros: number;
1039 proposedCostMicros: number;
1040 changePercent: number;
1041 markupPercent: number;
1042 reason: string;
1043 source: "keeper" | "reconciler" | string;
1044 /** Far off the current cost: look before approving. */
1045 suspect: boolean;
1046 status: "open" | "applied" | "approved" | "rejected" | "superseded" | string;
1047 createdAt: string;
1048 decidedAt: string | null;
1049 decidedBy: string | null;
1050 note: string | null;
1051 effectiveAt: string | null;
1052};
1053
1054/** One version of one meter's price; never changed once written. */
1055export type PriceVersion = {
1056 id: string;
1057 meter: string;
1058 version: number;
1059 costMicros: number;
1060 markupPercent: number;
1061 priceMicros: number;
1062 effectiveAt: string;
1063 reason: string;
1064 createdBy: string;
1065 appliedAt: string | null;
1066};
1067
1068export type WorkspaceCost = { workspace: string; costMicros: number; revenueMicros: number; internal: boolean };
1069
1070export type CostLineSummary = {
1071 product: string;
1072 meter: string;
1073 rawName: string;
1074 unit: string;
1075 source: string;
1076 quantity: number;
1077 costMicros: number;
1078 /** Absent when no mapping claims it. */
1079 bucket: string | null;
1080};
1081
1082export type CostMapping = {
1083 product: string;
1084 meter: string;
1085 bucket: string;
1086 priceMeter: string | null;
1087 ownMeter: string | null;
1088 scaleToOwn: boolean;
1089 driftPercent: number;
1090 note: string;
1091 updatedAt: string;
1092 updatedBy: string;
1093};
1094
1095export type CostMappingInput = {
1096 product: string;
1097 meter: string;
1098 bucket?: string;
1099 priceMeter?: string | null;
1100 ownMeter?: string | null;
1101 scaleToOwn?: boolean;
1102 driftPercent?: number | null;
1103 note?: string;
1104 remove?: boolean;
1105};
1106
1107export type CostSettings = {
1108 autoApply: boolean;
1109 autoApplyPercent: number;
1110 noticeDays: number;
1111 marginFloorPercent: number;
1112 alertDays: number;
1113 minDailyCostMicros: number;
1114 anomalyFactor: number;
1115 anomalyFloorMicros: number;
1116};
1117
1118export type CostsReport = {
1119 configured: boolean;
1120 fetchedAt: string | null;
1121 since: string;
1122 until: string;
1123 days: CostDay[];
1124 products: ProductMargin[];
1125 overall: OverallMargin;
1126 drift: CostDrift[];
1127 alerts: MarginAlert[];
1128 proposals: PriceProposal[];
1129 versions: PriceVersion[];
1130 topWorkspaces: WorkspaceCost[];
1131 lines: CostLineSummary[];
1132 mappings: CostMapping[];
1133 settings: CostSettings;
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1134 /** g1t's own spend against its two caps. */
1135 caps: SpendCaps;
1136};
1137
1138/** What g1t pays for itself, at cost, against its caps (billing's `budget`). */
1139export type SpendCaps = {
1140 /** Today (UTC), YYYY-MM-DD, and this month, YYYY-MM. */
1141 day: string;
1142 month: string;
1143 /** What g1t paid for itself today across every workspace. */
1144 todayMicros: number;
1145 /** `PLATFORM_DAILY_SPEND_CAP_MICROS`; 0: no breaker. */
1146 dailyCapMicros: number;
1147 /** New hosted-model agent runs g1t would pay for are paused. */
1148 tripped: boolean;
1149 trippedAt: string | null;
1150 liftedBy: string | null;
1151 liftedAt: string | null;
1152 liftNote: string | null;
1153 /** This month so far, by what paid: comped, trial, oss, given, unpaid. */
1154 monthBuckets: { bucket: string; title: string; micros: number }[];
1155 comped: CompedBudget[];
1156 /** Free workspaces' share of reconciled costs this month (git, storage, platform). */
1157 freeTierMicros: number;
1158 /** `CLOUDFLARE_FIXED_MONTHLY_MICROS`: Cloudflare subscriptions, an estimate. */
1159 fixedMonthlyMicros: number;
1160 /** Money in this month, through the last reconciled day. */
1161 revenueMicros: number;
1162};
1163
1164/** A comped account's monthly budget, at cost. */
1165export type CompedBudget = {
1166 account: string;
1167 name: string;
1168 usedMicros: number;
1169 /** 0: no budget. */
1170 ceilingMicros: number;
1171 /** `COMPED_MONTHLY_CEILING_MICROS`, not the account's own limit. */
1172 defaultCeiling: boolean;
1173 /** 50, 75, 90, 100, or 0. */
1174 level: number;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1175};
1176
1177export type CostsRun = { lines: number; days: number; proposals: number; alerts: number; problems: string[] };