Skip to content

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.sh
3,758 linesCodeBlameRaw

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.

The contracts no longer describe g1t's own agents, and workspaces can keep their AI providers. Every consumer had already stopped using them, so the TypeScript and Rust contracts drop the workspace-agent, ability, look, skill-library, context, runner-agent and mention modules, the chat and docs RPCs agents posted and read through, the folio agent methods, the agent_waiting notification, agent.asked and memory.changed events, AI credit, token and gateway billing types, model routes and sessions, team agents, agent tokens, plan, review, message and confidence types, command rules, cost caps and confidence rules. The agents:run and models:* scopes are no longer offered by any preset, OAuth default or permission form, but a stored token or grant that names them still reads; and the removed operations are gone from the scope table, so the API's check that every operation has exactly one scope is strict again. What stored data needs in order to parse (old run and credential kinds, an agent team lead, retired rules and webhook events, old guardrail and integration settings) still parses, and a run's token is still PrincipalKind::Agent, which now means a run's token and the @g1t rows written before. The customize, marketplace, skills and claude-plugin contracts stay only until the mobile app drops its Customize screens.1//! The billing service: what a workspace's usage costs, its plan, credit,
2//! limits and invoices.
Mission control counts people's direct pushes to the default branch3//!
The contracts no longer describe g1t's own agents, and workspaces can keep their AI providers. Every consumer had already stopped using them, so the TypeScript and Rust contracts drop the workspace-agent, ability, look, skill-library, context, runner-agent and mention modules, the chat and docs RPCs agents posted and read through, the folio agent methods, the agent_waiting notification, agent.asked and memory.changed events, AI credit, token and gateway billing types, model routes and sessions, team agents, agent tokens, plan, review, message and confidence types, command rules, cost caps and confidence rules. The agents:run and models:* scopes are no longer offered by any preset, OAuth default or permission form, but a stored token or grant that names them still reads; and the removed operations are gone from the scope table, so the API's check that every operation has exactly one scope is strict again. What stored data needs in order to parse (old run and credential kinds, an agent team lead, retired rules and webhook events, old guardrail and integration settings) still parses, and a run's token is still PrincipalKind::Agent, which now means a run's token and the @g1t rows written before. The customize, marketplace, skills and claude-plugin contracts stay only until the mobile app drops its Customize screens.4//! Money is held in millionths of a US dollar, so that a sandbox run
5//! costing a fraction of a cent is recorded exactly.
Mission control counts people's direct pushes to the default branch6//!
7//! Each `*Args` struct is the argument of the method of the same name,
8//! served at `POST /rpc/<method>`.
9
10use serde::{Deserialize, Serialize};
11
12use crate::repos::RepoPath;
13use crate::{User, Viewer};
14
15/// Millionths of a US dollar in one dollar.
16pub const MICROS_PER_DOLLAR: i64 = 1_000_000;
17
18/// Whether workspaces are charged for agents at all, and with real money.
19/// `status` takes nothing and returns this.
20#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
21pub struct Status {
22 /// False when no payment provider is configured: nothing is charged,
23 /// and who may run agents is decided some other way.
24 pub enabled: bool,
25 /// False while the payment provider is in its test mode, where cards
26 /// are not real.
27 pub live: bool,
28 /// True while g1t is being built out: runs are recorded, with what
29 /// they cost, but nothing is charged and no credit is needed. Not a
30 /// promise that it stays free.
31 #[serde(default)]
32 pub free: bool,
33}
34
35/// `trial`: a workspace's trial credit, so people can try g1t (its agents on
36/// g1t's hosted models among it) without a key or a card of their own. Each
37/// new workspace gets one grant of usage credit (`TRIAL_WORKSPACE_MICROS`),
38/// made when it first uses something, out of a pool for everyone that
39/// resets each calendar month (`TRIAL_MONTHLY_POOL_MICROS`). When this
40/// month's pool is given out, new grants wait for the next month. Returns
41/// `Trial`.
42#[derive(Debug, Serialize, Deserialize)]
43#[serde(rename_all = "camelCase")]
44pub struct TrialArgs {
45 pub workspace: String,
46 /// Workspaces open to hosted models anyway, whose use is not counted
47 /// against the pool.
48 #[serde(default)]
49 pub exempt: Vec<String>,
50}
51
52#[derive(Clone, Debug, Serialize, Deserialize)]
53#[serde(rename_all = "camelCase")]
54pub struct Trial {
55 /// Whether its agents may use g1t's hosted models on the trial now: it
56 /// has credit left, or this month's pool can still grant it some.
57 pub open: bool,
58 /// What the trial has paid for so far, in millionths of a dollar.
59 pub used_micros: i64,
60 /// Its grant, or what it would be granted.
61 pub limit_micros: i64,
62 /// No longer used: the trial does not end on a date. Kept for older
63 /// readers; always null.
64 pub ends_at: Option<String>,
65 /// Why it is closed: `off` (no trials), `used` (this workspace's grant
66 /// is spent) or `pool` (this month's grants are all given out; see
67 /// `waits_until`). `ended` is no longer sent.
68 pub reason: Option<String>,
69 /// Whether the workspace has its grant already.
70 #[serde(default)]
71 pub granted: bool,
72 /// RFC 3339: when a workspace waiting for a grant can get one, the
73 /// first of next month. Only with reason `pool`.
74 #[serde(default)]
75 pub waits_until: Option<String>,
76}
77
78/// A workspace's standing.
79#[derive(Clone, Debug, Serialize, Deserialize)]
80#[serde(rename_all = "camelCase")]
81pub struct Account {
82 pub workspace: String,
83 /// Credit left, in millionths of a dollar. Can dip below zero by the
84 /// cost of the runs that were under way when it ran out.
85 pub balance_micros: i64,
86 pub status: Status,
87 /// What is added to a run's cost, in percent.
88 pub margin_percent: u32,
89 /// The card g1t charges as the workspace nears its limit and when a
90 /// month closes, if one is on file.
91 #[serde(default)]
92 pub card: Option<Card>,
93}
94
95/// A saved card, as far as it is safe to show.
96#[derive(Clone, Debug, Serialize, Deserialize)]
97#[serde(rename_all = "camelCase")]
98pub struct Card {
99 /// `visa`, `mastercard`, ...
100 pub brand: String,
101 pub last4: String,
102 pub exp_month: u32,
103 pub exp_year: u32,
104}
105
106/// `billing_portal`: Stripe's hosted billing page for the workspace, where
107/// an owner adds or replaces the card, sees invoices and receipts, and sets
108/// the billing email and address. g1t never handles card numbers. Owners
109/// only. Returns `Outcome<Checkout>` (its `url`); Stripe sends them back
110/// to `return_url`.
111#[derive(Debug, Serialize, Deserialize)]
112pub struct BillingPortalArgs {
113 pub actor: User,
114 pub workspace: String,
115 pub return_url: String,
116}
117
118/// `admin_billing_link`: for staff to send a customer: their Stripe billing
119/// page. Returns `Outcome<BillingLink>`.
120#[derive(Debug, Serialize, Deserialize)]
121pub struct AdminBillingLinkArgs {
122 pub workspace: String,
123 pub by: String,
124}
125
126#[derive(Clone, Debug, Serialize, Deserialize)]
127#[serde(rename_all = "camelCase")]
128pub struct BillingLink {
129 /// A one-time session on Stripe's billing page, signed in already.
130 pub portal_url: String,
131 /// The billing page's sign-in page, which does not expire: the
132 /// customer signs in with the email Stripe has for them.
133 pub login_url: Option<String>,
134 pub customer_email: Option<String>,
135 pub expires_note: String,
136}
137
138#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
139#[serde(rename_all = "snake_case")]
140pub enum EntryKind {
141 /// Credit bought with a card.
142 TopUp,
143 /// An agent's run, or a paid feature's usage past its allowance.
144 Usage,
145}
146
147/// One line of a workspace's statement.
148#[derive(Clone, Debug, Serialize, Deserialize)]
149#[serde(rename_all = "camelCase")]
150pub struct LedgerEntry {
151 pub id: String,
152 pub kind: EntryKind,
153 /// Positive for credit added, negative for usage.
154 pub amount_micros: i64,
155 pub description: String,
156 /// For usage: the repository and pull request the agent worked on.
157 pub repo: Option<String>,
158 pub number: Option<u32>,
159 /// For usage: `implement`, `review` or `update`.
160 pub task: Option<String>,
161 /// For usage: the model, by its public name.
162 pub model: Option<String>,
163 /// For usage: `g1t` when g1t paid the model provider, `workspace` when
164 /// the workspace's own account did. Runs on the workspace's own
165 /// provider pay only their sandbox time now, so only older entries
166 /// are `workspace`.
167 #[serde(default = "g1t")]
168 pub billed_to: String,
169 /// For a top-up: the username of whoever paid.
170 pub created_by: Option<String>,
171 /// RFC 3339.
172 pub created_at: String,
173 /// The workspace the line belongs to, which tells an enterprise's
174 /// lines apart.
175 #[serde(default, skip_serializing_if = "Option::is_none")]
176 pub workspace: Option<String>,
177 /// For usage: what the g1t plan's monthly included usage paid of it.
178 /// The entry's `amount_micros` is what is left to pay.
179 #[serde(default)]
180 pub credit_micros: i64,
181 /// For usage: what the workspace's trial credit paid of it.
182 #[serde(default)]
183 pub trial_micros: i64,
184 /// For usage: what g1t's open-source pool paid of it.
185 #[serde(default)]
186 pub oss_micros: i64,
187 /// For usage: what g1t covered itself, such as the part of a free
188 /// workspace's last trial run that went past its trial credit.
189 #[serde(default)]
190 pub given_micros: i64,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging191 /// For usage: what the account's discount took off its price. The
192 /// price is `-amount_micros` plus this and what paid for it.
193 #[serde(default)]
194 pub discount_micros: i64,
195 /// For a credit from g1t, and for what of one expired or was revoked:
196 /// its kind.
197 #[serde(default, skip_serializing_if = "Option::is_none")]
198 pub credit_kind: Option<CreditKind>,
Mission control counts people's direct pushes to the default branch199}
200
201fn g1t() -> String {
202 "g1t".to_owned()
203}
204
205/// `account` (`Outcome<Account>`) and `ledger` (`Outcome<Vec<LedgerEntry>>`,
206/// newest first). Members of the workspace only.
207#[derive(Debug, Serialize, Deserialize)]
208pub struct AccountArgs {
209 pub workspace: String,
210 pub viewer: Viewer,
211}
212
213/// `checkout`: prepays usage: money paid in advance, drawn down by usage
214/// after the plan's included usage, which raises what can be used before
215/// work stops by the same amount at once. $25 at the least. By card, with
216/// 3-D Secure; from $1,000 also by bank transfer. Owners of the workspace
217/// only. Returns `Outcome<Checkout>`.
218#[derive(Debug, Serialize, Deserialize)]
219#[serde(rename_all = "camelCase")]
220pub struct CheckoutArgs {
221 pub actor: User,
222 pub workspace: String,
223 /// How much to prepay, in cents.
224 pub amount_cents: u32,
225 /// Where the payment page sends the person afterwards. The payment's
226 /// id is appended as `session`.
227 pub return_url: String,
228 /// `card` (the default) or `bank_transfer` (from $1,000): Stripe gives
229 /// the account details, and the money counts once it arrives.
230 #[serde(default)]
231 pub method: Option<String>,
232}
233
234#[derive(Debug, Serialize, Deserialize)]
235pub struct Checkout {
236 /// The payment page to send the person to.
237 pub url: String,
238}
239
240/// `confirm`: credits a payment once the provider says it was made. Safe
241/// to call any number of times. Returns `Outcome<Account>`.
242#[derive(Debug, Serialize, Deserialize)]
243pub struct ConfirmArgs {
244 pub workspace: String,
245 pub viewer: Viewer,
246 /// The payment's id, as returned to `return_url`.
247 pub session: String,
248}
249
250/// `usage`: what a workspace's agents cost over a period, broken down.
251/// Members only. Returns `Outcome<Usage>`.
252#[derive(Debug, Serialize, Deserialize)]
253pub struct UsageArgs {
254 pub workspace: String,
255 pub viewer: Viewer,
256 /// RFC 3339: the start of the period. The period runs to now.
257 pub since: String,
258}
259
260/// One slice of usage: what it was for, what it cost, how many runs.
261#[derive(Clone, Debug, Serialize, Deserialize)]
262#[serde(rename_all = "camelCase")]
263pub struct UsageSlice {
264 pub key: String,
265 pub micros: i64,
266 pub runs: u32,
267}
268
269/// What a workspace's agents cost over a period.
270#[derive(Clone, Debug, Serialize, Deserialize)]
271#[serde(rename_all = "camelCase")]
272pub struct Usage {
273 pub since: String,
274 /// Charged, including g1t's margin.
275 pub spent_micros: i64,
Billing and Usage reconcile: own-provider runs leave Billing's at-price total, and Usage's not-charged part is at price less charged276 /// What g1t's usage came to at price, less what was charged: the plan's
277 /// included usage, the trial, a pool or a free period paid it. Usage at
278 /// price is `spent_micros` plus this.
Billing's usage total is labeled at price, and Usage says what part of it was paid for279 #[serde(default)]
280 pub covered_micros: i64,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging281 /// What the account's discount took off the price. Usage at price is
282 /// `spent_micros` plus `covered_micros` plus this.
283 #[serde(default)]
284 pub discount_micros: i64,
285 /// The account's discount now, in percent; absent without one. With
286 /// one, the slices measure usage at price.
287 #[serde(default)]
288 pub discount_percent: Option<u32>,
Usage, Billing settings and prepaid AI credit; fixes from the UX audit289 /// Usage at price: `spent_micros` plus `covered_micros` plus
290 /// `discount_micros`, from the same ledger lines. The one figure every
291 /// page shows as usage (mission control, the agent fleet, Usage and
292 /// Billing), labelled "usage at price".
293 #[serde(default)]
294 pub price_micros: i64,
Mission control counts people's direct pushes to the default branch295 /// What g1t's model provider charged, before the margin.
296 pub cost_micros: i64,
297 /// What runs on the workspace's own provider cost there, as the harness
298 /// estimated it. Not charged by g1t.
299 pub provider_micros: i64,
300 /// What the runs used, at cost: g1t's models and the workspace's own
301 /// provider together, whatever was charged for them.
302 pub used_micros: i64,
303 /// g1t charges nothing for now. The slices then measure usage at cost,
304 /// since every charge is zero.
305 pub free: bool,
306 pub runs: u32,
307 /// Spend per day (`YYYY-MM-DD`) and task, as `day/task` keys.
308 pub by_day: Vec<UsageSlice>,
309 /// Per task: implement, review, revise, update, plan.
310 pub by_task: Vec<UsageSlice>,
311 /// Per repository, `namespace/name`.
312 pub by_repo: Vec<UsageSlice>,
313 /// The pull requests that cost most, as `namespace/name#number`.
314 pub by_pull: Vec<UsageSlice>,
315 /// Per model, by its public name.
316 pub by_model: Vec<UsageSlice>,
317 /// Credit bought in the period.
318 pub added_micros: i64,
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens319}
320
Mission control counts people's direct pushes to the default branch321/// What a workspace pays a monthly price for. There is one plan, `plan`
322/// ("g1t"): a flat price per workspace, never per person, with included
323/// usage each month, more private storage, and deployments. Never free:
324/// `FREE_WHILE_BUILDING` does not cover it.
325///
326/// `deployments` is not sold on its own any more: it comes with the plan.
327/// A service that asks `has_feature` for it is told whether the workspace
328/// has the plan, and a Deployments subscription bought before the change
329/// keeps working until its period ends.
330#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
331#[serde(rename_all = "snake_case")]
332pub enum Feature {
333 /// The g1t plan. Older readers called it `team`.
334 #[serde(alias = "team")]
335 Plan,
336 /// Previews per pull request and production on g1t.page: part of the
337 /// plan.
338 Deployments,
Pricing says it plainly: models at the provider's price, the agent rate for what g1t runs around every model call (the gateway, secrets, routing, context and pass-through to your own provider, so your own keys too), everything else at cost plus 20%, your own runners free, no seats; Security and quality comes with the plan with no separate fee, and live activations end. Each agent has an effort setting, Auto to Max, with what a typical task has cost at each level, and Spend's Spend less, keep quality suggests a lower level only when the agent's own past work shows quality held, to apply or dismiss. The pricing, spend and agents guides say how.339 /// Security and quality: the security suite's paid features on private
340 /// repositories. It comes with the plan; the price book's
341 /// `security_activation` is $0, and its scans are metered like
342 /// everything else.
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar343 Security,
Mission control counts people's direct pushes to the default branch344}
345
346impl Feature {
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar347 /// What is sold: the plan, and the Security and quality activation.
348 pub const ALL: [Feature; 2] = [Feature::Plan, Feature::Security];
Mission control counts people's direct pushes to the default branch349
350 pub fn as_str(self) -> &'static str {
351 match self {
352 Feature::Plan => "plan",
353 Feature::Deployments => "deployments",
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar354 Feature::Security => "security",
Mission control counts people's direct pushes to the default branch355 }
356 }
357
358 pub fn parse(name: &str) -> Option<Feature> {
359 match name {
360 "plan" | "team" => Some(Feature::Plan),
361 "deployments" => Some(Feature::Deployments),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar362 "security" => Some(Feature::Security),
Mission control counts people's direct pushes to the default branch363 _ => None,
364 }
365 }
366
367 pub fn title(self) -> &'static str {
368 match self {
369 Feature::Plan => "g1t",
370 Feature::Deployments => "Deployments",
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar371 Feature::Security => "Security and quality",
Mission control counts people's direct pushes to the default branch372 }
373 }
374}
375
376/// What deployments cost g1t, in millionths of a dollar: fallbacks for
377/// when billing's price book cannot be read. Nothing here is an allowance:
378/// on the plan every unit is metered from the first, at cost plus the
379/// margin, and drawn from the plan's included usage before anything is
380/// charged. Projects, previews and the apps behind them are not metered at
381/// all: Cloudflare's Workers for Platforms includes far more scripts than
382/// g1t runs, so an app costs g1t only the requests and CPU it answers with.
383pub mod deployment_costs {
384 /// Workers for Platforms: $0.30 per million requests.
385 pub const MICROS_PER_MILLION_REQUESTS: i64 = 300_000;
386 /// $0.02 per million CPU milliseconds.
387 pub const MICROS_PER_MILLION_CPU_MS: i64 = 20_000;
388 /// What one second of a build's sandbox costs g1t (Cloudflare
389 /// Containers, standard-1: half a vCPU, 4 GiB, 8 GB disk), rounded up,
390 /// as the price keeper measured it on 2026-10-05 (14.5). Only a
391 /// fallback: billing charges builds at the price book's `build_second`,
392 /// which the keeper keeps current.
393 pub const MICROS_PER_BUILD_SECOND: i64 = 15;
394 /// What one custom hostname costs g1t a month (Cloudflare for SaaS):
395 /// $0.10.
396 pub const MICROS_PER_DOMAIN_MONTH: i64 = 100_000;
Merge GitHub pull request #8 (claude/cool-newton-7nm8r9): Docker deployments on g1t.page behind a switch that stays off until Cloudflare's container APIs are checked live, workflows a workspace manages in its repositories, tarball and zipball downloads, refs/pull/* kept to g1t alone, framework detection for g1t.page builds, and a workflow's event payload matching GitHub's.397 /// Container apps (Docker deployments), at Cloudflare Containers' list
398 /// prices: a vCPU-second, a GiB-second of memory and a GB-second of
399 /// disk while awake, the Durable Object in front of each instance a
400 /// second while it runs, and a GB sent at the most Cloudflare charges
401 /// for one anywhere. The price book's `app_container_*` meters.
402 pub const MICROS_PER_CONTAINER_VCPU_SECOND: f64 = 20.0;
403 pub const MICROS_PER_CONTAINER_GIB_SECOND: f64 = 2.5;
404 pub const MICROS_PER_CONTAINER_DISK_GB_SECOND: f64 = 0.07;
405 pub const MICROS_PER_CONTAINER_SECOND: f64 = 1.5625;
406 pub const MICROS_PER_CONTAINER_EGRESS_GB: i64 = 50_000;
Mission control counts people's direct pushes to the default branch407}
408
409/// `record_sandbox`: how long one sandbox ran for a workspace, reported by
410/// the runner when it stops. Every sandbox g1t starts for a workspace
411/// (agents, reviews, checks, the merge queue, workflow jobs) is metered by
412/// the second, from the first: recorded once per `reference`, with what it
413/// cost g1t, and charged at the price book's `sandbox_second` price unless
414/// `FREE_WHILE_BUILDING`. Deploy builds are charged by the Deployments plan
415/// instead.
416/// Returns `Outcome<bool>`: false if that reference was recorded before.
417#[derive(Debug, Serialize, Deserialize)]
418#[serde(rename_all = "camelCase")]
419pub struct RecordSandboxArgs {
420 pub workspace: String,
421 pub seconds: u32,
422 /// What ran, e.g. `Checks on acme/api#12`.
423 pub description: String,
424 /// `namespace/name`.
425 pub repo: Option<String>,
426 /// Unique to the run.
427 pub reference: String,
The contracts no longer describe g1t's own agents, and workspaces can keep their AI providers. Every consumer had already stopped using them, so the TypeScript and Rust contracts drop the workspace-agent, ability, look, skill-library, context, runner-agent and mention modules, the chat and docs RPCs agents posted and read through, the folio agent methods, the agent_waiting notification, agent.asked and memory.changed events, AI credit, token and gateway billing types, model routes and sessions, team agents, agent tokens, plan, review, message and confidence types, command rules, cost caps and confidence rules. The agents:run and models:* scopes are no longer offered by any preset, OAuth default or permission form, but a stored token or grant that names them still reads; and the removed operations are gone from the scope table, so the API's check that every operation has exactly one scope is strict again. What stored data needs in order to parse (old run and credential kinds, an agent team lead, retired rules and webhook events, old guardrail and integration settings) still parses, and a run's token is still PrincipalKind::Agent, which now means a run's token and the @g1t rows written before. The customize, marketplace, skills and claude-plugin contracts stay only until the mobile app drops its Customize screens.428 /// What ran: `check`, `workflow`, `queue` or `deploy`. Decides whether
Mission control counts people's direct pushes to the default branch429 /// g1t's open-source pool may pay for it (checks, workflows and the
430 /// merge queue on public repositories). Absent: not the pool.
431 #[serde(default)]
432 pub kind: Option<ComputeKind>,
433 /// The vCPU-seconds the sandbox used, when it can tell. With it, the
434 /// run is priced on its own CPU (`sandbox_base_second` per second plus
435 /// `sandbox_cpu_second` per vCPU-second); without it, at the average
436 /// (`sandbox_second`).
437 #[serde(default, alias = "cpu_seconds")]
438 pub cpu_seconds: Option<f64>,
439 /// The reservation the work started under, settled with this cost.
440 #[serde(default, alias = "reservation_id")]
441 pub reservation_id: Option<String>,
442 /// It ran on one of the workspace's self-hosted runners: recorded as
443 /// self-hosted time, for the minutes, at $0.
444 #[serde(default, alias = "self_hosted")]
445 pub self_hosted: bool,
446 /// The machine it ran on, by label (`g1t-4core`); absent, the standard
447 /// one. A larger machine's memory and disk cost more each second.
448 #[serde(default)]
449 pub instance: Option<String>,
450}
451
452/// How much a workspace has earned g1t's trust with money, which sets how
453/// far its unpaid usage can go before its work stops.
454#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
455#[serde(rename_all = "snake_case")]
456pub enum Trust {
457 /// No live payment yet: only a little past the free allowances.
458 New,
459 /// Has paid g1t real money: the ceiling grows with what it has paid.
460 Paid,
461 /// Has paid steadily for months, with nothing disputed or declined:
462 /// the ceiling follows its monthly spend, up to $10,000, by itself.
463 Established,
464 /// A ceiling g1t set by hand, after talking to the workspace.
465 Reviewed,
466 /// g1t's own workspaces: no ceiling.
467 Internal,
468}
469
470#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
471#[serde(rename_all = "snake_case")]
472pub enum LimitState {
473 Ok,
474 /// Past 80% of the ceiling.
475 Warning,
476 /// At or past it: no new sandboxes, builds or app requests.
477 Stopped,
478}
479
480/// How far a workspace's unpaid usage has gone this month, and where its
481/// work stops: like Fly's or Cloudflare's limits for new accounts, so no
482/// one runs up costs g1t cannot collect. Usage counts at what it cost g1t
483/// or what it is charged, whichever is more, so it counts while g1t is
484/// free too.
485#[derive(Clone, Debug, Serialize, Deserialize)]
486#[serde(rename_all = "camelCase")]
487pub struct Limit {
488 pub workspace: String,
489 /// The account that pays, whose usage and payments the limit counts:
490 /// the workspace's own, or its enterprise's.
491 #[serde(default)]
492 pub account: String,
493 #[serde(default)]
494 pub account_name: String,
495 pub trust: Trust,
496 /// Usage this month (UTC) less what was paid this month.
497 pub exposure_micros: i64,
498 /// Where work stops: the lower of g1t's ceiling and the owner's own
499 /// spend limit. None for g1t's own workspaces.
500 pub ceiling_micros: Option<i64>,
501 /// The ceiling g1t sets from `trust`.
502 pub trust_ceiling_micros: Option<i64>,
503 /// The owner's own monthly limit, if they set one.
504 pub spend_limit_micros: Option<i64>,
505 pub state: LimitState,
506 /// What to tell people when work is stopped or close to it.
507 pub message: Option<String>,
Spend adds up on one ledger. Charged this month has one definition, price less discount, included usage and credit, shared by the plan card, the spend limit, Spend and the top bar; the limit had counted usage not yet closed at full price before the discount, so a comped workspace read as charged a cent. Every agent line on the ledger names the agent and who asked, repository runs by g1t included, so Spent is the sum of its products, Agents is the agent product, and by agent adds up to it; the billing API returns by_agent and by_person. The usage and billing guide says how spend is counted.508 /// Charged this month, which the spend limit is measured against: the
509 /// month's usage at price, less the account's discount, what the
510 /// plan's included usage, the trial or a pool paid, and what credit
511 /// paid; usage metered through the month and charged when it closes
512 /// counted on the same terms. The one figure the Billing page's plan
513 /// card, Spend's "Charged" and the top bar show (`UsageTotals::charged_micros`
514 /// over the month is the same number).
Mission control counts people's direct pushes to the default branch515 #[serde(default)]
516 pub spent_micros: i64,
517 /// True while the owners have not chosen a spend limit of their own, so
518 /// the automatic one applies: $200, or twice last month's spend.
519 #[serde(default)]
520 pub default_spend_limit: bool,
521 /// The most the owners may set their own limit to: g1t's ceiling. To
522 /// go past it, they contact g1t.
523 #[serde(default)]
524 pub available_micros: Option<i64>,
525 /// How the ceiling grows from here, in a sentence.
526 #[serde(default)]
527 pub growth: Option<String>,
528 /// Money paid in advance and not used yet. It raises what can be used
529 /// before work stops by the same amount, at once.
530 #[serde(default)]
531 pub prepaid_micros: i64,
532 /// The highest ceiling the workspace has ever had. Owners may set their
533 /// spend limit anywhere up to it (plus what is prepaid) without asking.
534 #[serde(default)]
535 pub max_ceiling_micros: Option<i64>,
536 /// The most the owners may raise the limit to themselves, once, with
537 /// `raise_once`: twice the highest ceiling. None once it is used.
538 #[serde(default)]
539 pub raise_once_micros: Option<i64>,
540 /// When the one-time raise was used, RFC 3339.
541 #[serde(default)]
542 pub raised_at: Option<String>,
543 /// True in a paid workspace's first billing cycle, when the ceiling is
544 /// the starting one (`LIMIT_PAID_START_MICROS`).
545 #[serde(default)]
546 pub first_month: bool,
Usage, Billing settings and prepaid AI credit; fixes from the UX audit547 /// The budget's alerts, in percent of the spend limit: some of 50, 75,
548 /// 90 and 100. Each is emailed to the owners once a month.
549 #[serde(default)]
550 pub alert_levels: Vec<u32>,
551 /// Whether usage pauses at the spend limit (the default). Off, the
552 /// limit only alerts; g1t's own ceiling still applies.
553 #[serde(default = "yes")]
554 pub pause_at_limit: bool,
555 /// An HTTPS address told of each budget alert with a JSON POST.
556 #[serde(default)]
557 pub budget_webhook: Option<String>,
Mission control counts people's direct pushes to the default branch558}
559
Usage, Billing settings and prepaid AI credit; fixes from the UX audit560fn yes() -> bool {
561 true
562}
563
Mission control counts people's direct pushes to the default branch564/// `limit`: a workspace's limit, for its members. Returns `Outcome<Limit>`.
565#[derive(Debug, Serialize, Deserialize)]
566pub struct LimitArgs {
567 pub workspace: String,
568 pub viewer: Viewer,
569}
570
571/// `check_limit`: the same, for the services that enforce it. Returns
572/// `Outcome<Limit>`.
573#[derive(Debug, Serialize, Deserialize)]
574pub struct CheckLimitArgs {
575 pub workspace: String,
576}
577
578/// `note_pending`: usage this month that will be charged later, such as
579/// app traffic past a plan, so the workspace's limit counts it now. Each
580/// report replaces the last for that workspace, source and month. Called
581/// by the service that meters it. Returns `bool`.
582#[derive(Debug, Serialize, Deserialize)]
583#[serde(rename_all = "camelCase")]
584pub struct NotePendingArgs {
585 pub workspace: String,
586 /// `deployments`, `security` (scans), `context` (search embeddings),
587 /// `storage` or `cache` (actions/cache, plan only). Billing charges
588 /// `security`, `context`, `storage` and `cache` itself once the month
589 /// is over; `deployments` charges its own.
590 pub source: String,
591 /// What it cost g1t so far this month, before the margin.
592 pub cost_micros: i64,
593 /// How much of it, for the Billing page: `1.2 million requests and
594 /// 3.4 million CPU ms`, `2 custom domains`.
595 #[serde(default)]
596 pub detail: Option<String>,
597}
598
599/// `usage_meters`: this month's usage for a workspace, one line per kind
600/// of meter, at what it is charged (cost plus the margin, on the account's
601/// terms) before the plan's included usage, the trial or g1t's pools paid
602/// for any of it. Members only. Returns `Outcome<Vec<MeterUsage>>`.
603#[derive(Debug, Serialize, Deserialize)]
604pub struct UsageMetersArgs {
605 pub workspace: String,
606 pub viewer: Viewer,
607}
608
609/// One kind of meter's usage this month.
610#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
611#[serde(rename_all = "camelCase")]
612pub struct MeterUsage {
613 /// `agents` (agent runs, models and sandboxes for checks, workflows
614 /// and the merge queue), `builds`, `requests` (app requests and CPU),
615 /// `domains`, `git_storage` (git operations and private storage) or
616 /// `search_scans` (search embeddings and security scans).
617 pub key: String,
618 pub label: String,
619 /// At price, before what paid for it.
620 pub micros: i64,
621 /// How much, when it is known: `12 runs`, `41 build minutes`.
622 #[serde(default)]
623 pub quantity: Option<String>,
624}
625
626/// `set_spend_limit`: the owner's own monthly ceiling, under g1t's; None
627/// removes it. Owners only. Returns `Outcome<Limit>`.
628#[derive(Debug, Serialize, Deserialize)]
629#[serde(rename_all = "camelCase")]
630pub struct SetSpendLimitArgs {
631 pub actor: User,
632 pub workspace: String,
633 /// A monthly limit, at most what is available; None goes back to the
634 /// default.
635 pub spend_limit_micros: Option<i64>,
636 /// Use everything available, with no limit of their own.
637 #[serde(default)]
638 pub use_full_limit: bool,
639 /// Use the one-time raise: up to twice the highest ceiling the
640 /// workspace has had, without asking. Once per workspace.
641 #[serde(default, alias = "raiseOnce")]
642 pub raise_once: bool,
643}
644
645/// One metered unit: what it costs g1t, and what it is sold at. The price
646/// is always `cost × (100 + markup) / 100`, so it follows the cost.
647#[derive(Clone, Debug, Serialize, Deserialize)]
648#[serde(rename_all = "camelCase")]
649pub struct Price {
650 /// `sandbox_second`, `build_second`, `app_requests`, `app_cpu`, `app_month`.
651 pub meter: String,
652 pub title: String,
653 pub unit: String,
654 /// Millionths of a dollar per unit; may have a fraction.
655 pub cost_micros: f64,
656 pub markup_percent: u32,
657 pub price_micros: f64,
658 /// `list`: Cloudflare's published price. `cloudflare`: what Cloudflare
659 /// actually billed g1t, measured.
660 pub source: String,
661 /// When it was last checked against Cloudflare's bill.
662 pub checked_at: Option<String>,
663 pub updated_at: String,
664}
665
666impl Price {
667 pub fn price_for(cost_micros: f64, markup_percent: u32) -> f64 {
668 cost_micros * f64::from(100 + markup_percent) / 100.0
669 }
670}
671
672/// A cost that moved.
673#[derive(Clone, Debug, Serialize, Deserialize)]
674#[serde(rename_all = "camelCase")]
675pub struct PriceChange {
676 pub meter: String,
677 pub old_cost_micros: f64,
678 pub new_cost_micros: f64,
679 pub markup_percent: u32,
680 /// The markup before, when the change was to the markup rather than
681 /// to the cost. Absent when the markup stayed `markup_percent`.
682 #[serde(default, skip_serializing_if = "Option::is_none")]
683 pub old_markup_percent: Option<u32>,
684 pub reason: String,
685 pub created_at: String,
686 /// When a change still to come takes effect: a rise is announced
687 /// before it is charged. Absent for changes already made.
688 #[serde(default, skip_serializing_if = "Option::is_none")]
689 pub effective_at: Option<String>,
690}
691
692/// `prices`: every metered price and the recent changes. Public. Returns
693/// `PriceBook`.
694#[derive(Clone, Debug, Serialize, Deserialize)]
695#[serde(rename_all = "camelCase")]
696pub struct PriceBook {
697 pub prices: Vec<Price>,
698 pub changes: Vec<PriceChange>,
699 /// The margin on model usage, which is charged at what AI Gateway
700 /// priced each request at.
701 pub model_margin_percent: u32,
702 /// Every plan, as it is sold now.
703 #[serde(default)]
704 pub plans: Vec<Plan>,
705 /// What is free, and what pays for it.
706 #[serde(default)]
707 pub free: Option<FreeTier>,
708}
709
710/// What g1t gives without a plan, each with what pays for it: a capped
711/// budget, never an open-ended allowance.
712#[derive(Clone, Debug, Default, Serialize, Deserialize)]
713#[serde(rename_all = "camelCase")]
714pub struct FreeTier {
715 /// Each new workspace's trial credit, once.
716 pub trial_workspace_micros: i64,
717 /// Trial grants each month, in all; new trials wait when it is spent.
718 pub trial_monthly_pool_micros: i64,
719 /// g1t's open-source pool each month, and any one repository's share.
720 pub oss_pool_micros: i64,
721 pub oss_repo_micros: i64,
722 /// Private repository storage that is free for every workspace. Past
723 /// it, the plan pays at cost plus the margin; a free workspace's pushes
724 /// to private repositories stop instead.
725 pub free_private_storage_bytes: i64,
726 /// Days of audit log a free workspace keeps.
727 pub audit_retention_days: u32,
728 /// Days of audit log the g1t plan keeps, and g1t's own and enterprise
729 /// workspaces. Longer is by arrangement, set per account in sudo.
730 #[serde(default)]
731 pub plan_audit_retention_days: u32,
732 /// The smallest amount a card is charged when a month closes; less
733 /// carries over. Charges at a limit always go through.
734 pub min_charge_micros: i64,
735 /// Git operations (clones, fetches and pushes through g1t) that are
736 /// free for every workspace each month. Past it, the plan pays at cost
737 /// plus the margin and is never slowed; a free workspace is slowed
738 /// down, never charged.
739 #[serde(default)]
740 pub git_operations_included: u64,
741 /// A new paid workspace's ceiling in its first month.
742 #[serde(default)]
743 pub paid_start_ceiling_micros: i64,
744 /// The most a one-click goodwill credit can cost g1t.
745 #[serde(default)]
746 pub overage_forgive_cost_micros: i64,
747}
748
749/// Who pays: a billing account. Every workspace has one; by default its
750/// own. An enterprise account pays for several workspaces at once, as
751/// GitHub Enterprise does: one bill, one limit, one set of terms.
752#[derive(Clone, Debug, Serialize, Deserialize)]
753#[serde(rename_all = "camelCase")]
754pub struct BillingAccount {
755 /// `ws_<slug>` for a workspace's own account; `ent_…` for an enterprise.
756 pub id: String,
757 pub kind: AccountKind,
758 pub name: String,
759 pub terms: Terms,
760 /// The workspaces it pays for.
761 pub workspaces: Vec<String>,
762 /// Where an enterprise's invoices go.
763 #[serde(default)]
764 pub billing_email: Option<String>,
765 /// An enterprise's invoices, newest first. Empty for a workspace's own.
766 #[serde(default)]
767 pub invoices: Vec<EnterpriseInvoice>,
768 pub created_at: String,
769 /// What g1t staff set for the account beyond its terms.
770 #[serde(default)]
771 pub allowances: Allowances,
772}
773
774/// Set per account by g1t staff in sudo, on top of its terms.
775#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
776#[serde(rename_all = "camelCase")]
777pub struct Allowances {
778 /// The g1t plan without paying for its monthly price, such as for a
779 /// partner. Usage is charged as usual. Comped accounts have it anyway.
780 #[serde(default, alias = "team")]
781 pub plan: bool,
782 /// Each of the account's public repositories' monthly cap on g1t's
783 /// open-source pool, in place of `OSS_REPO_MICROS`. None: the default.
784 #[serde(default)]
785 pub oss_repo_micros: Option<i64>,
786 /// The trial credit each of its workspaces gets, in place of
787 /// `TRIAL_WORKSPACE_MICROS`, outside the monthly pool. None: the default.
788 #[serde(default)]
789 pub trial_micros: Option<i64>,
790 /// Agents at once, in place of the plan's (2 in the first month or on
791 /// the trial, then 10). None: the default.
792 #[serde(default)]
793 pub max_concurrent_agents: Option<u32>,
794 /// One run's spend cap, in place of `RUN_CAP_MICROS` and the owners'
795 /// own. None: theirs, or the default.
796 #[serde(default)]
797 pub run_cap_micros: Option<i64>,
798 /// What the agents on one issue may spend in all, in place of
799 /// `ISSUE_CAP_MICROS` and the owners' own. None: theirs, or the default.
800 #[serde(default)]
801 pub issue_cap_micros: Option<i64>,
802 /// Days of audit log its workspaces keep, in place of the plan's (7
803 /// free, 90 on the plan), longer or shorter. None: the plan's.
804 #[serde(default)]
805 pub audit_retention_days: Option<u32>,
806 /// A hold g1t staff put on new compute, with why. None: no hold.
807 #[serde(default)]
808 pub hold: Option<String>,
809}
810
811/// `admin_set_allowances`: the plan on or off without charge, overrides of
812/// the plan's caps, a hold, and the account's share of g1t's pools.
813/// Recorded with who and why. Returns `Outcome<BillingAccount>`.
814#[derive(Debug, Serialize, Deserialize)]
815pub struct AdminSetAllowancesArgs {
816 pub id: String,
817 pub allowances: Allowances,
818 pub note: String,
819 pub by: String,
820}
821
822// --- Entitlements, and compute started under a reservation -----------------
823//
824// Every service that starts compute (sandboxes for agents, checks,
825// workflows and the merge queue; builds; models; semantic search) asks
826// billing first:
827//
828// 1. `entitlements { workspace }` says what the workspace may do at all:
829// its plan, whether it may start compute, its caps, and whether compute
830// is paused.
831// 2. `reserve { workspace, repo, public, kind, estimate_micros }` holds the
832// work's estimated cost against what may pay for it, so that starts at
833// the same moment cannot overshoot the ceiling together. It answers who
834// pays first, or refuses with a stable code and a message for the owner.
835// 3. `settle { reservation_id, actual_micros }` releases the hold once the
836// work is done. The charge itself goes on the ledger the usual way
837// (`finish_run`, `record_sandbox`, `charge_feature`, `note_pending`).
838//
839// A reservation never settled expires after `RESERVATION_HOURS`.
840
841/// A reservation that is never settled stops holding after this long.
842pub const RESERVATION_HOURS: u64 = 3;
843/// What a ceiling reads as when there is none (g1t's own workspaces): a
844/// billion dollars, which JavaScript holds exactly.
845pub const UNLIMITED_MICROS: i64 = 1_000_000_000_000_000;
846
847/// What a workspace pays g1t on, as far as compute is concerned.
848#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
849#[serde(rename_all = "snake_case")]
850pub enum PlanKind {
851 /// No plan: the forge is free; compute only from a trial or g1t's
852 /// open-source pool, after a card check.
853 Free,
854 /// The g1t plan, paid for (or given by g1t staff without its price).
855 Paid,
856 /// g1t's own workspaces and Flagon's (comped terms): the plan without
857 /// being charged. Usage is still recorded at what it cost.
858 Internal,
859 /// Paid for by an enterprise account, invoiced.
860 Enterprise,
861}
862
863impl PlanKind {
864 pub fn as_str(self) -> &'static str {
865 match self {
866 PlanKind::Free => "free",
867 PlanKind::Paid => "paid",
868 PlanKind::Internal => "internal",
869 PlanKind::Enterprise => "enterprise",
870 }
871 }
872
873 /// Whether usage past what is included may be charged (on demand).
874 pub fn on_demand(self) -> bool {
875 !matches!(self, PlanKind::Free)
876 }
877}
878
879/// What compute is for.
880#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
881#[serde(rename_all = "snake_case")]
882pub enum ComputeKind {
The contracts no longer describe g1t's own agents, and workspaces can keep their AI providers. Every consumer had already stopped using them, so the TypeScript and Rust contracts drop the workspace-agent, ability, look, skill-library, context, runner-agent and mention modules, the chat and docs RPCs agents posted and read through, the folio agent methods, the agent_waiting notification, agent.asked and memory.changed events, AI credit, token and gateway billing types, model routes and sessions, team agents, agent tokens, plan, review, message and confidence types, command rules, cost caps and confidence rules. The agents:run and models:* scopes are no longer offered by any preset, OAuth default or permission form, but a stored token or grant that names them still reads; and the removed operations are gone from the scope table, so the API's check that every operation has exactly one scope is strict again. What stored data needs in order to parse (old run and credential kinds, an agent team lead, retired rules and webhook events, old guardrail and integration settings) still parses, and a run's token is still PrincipalKind::Agent, which now means a run's token and the @g1t rows written before. The customize, marketplace, skills and claude-plugin contracts stay only until the mobile app drops its Customize screens.883 /// An agent run of g1t's own, retired: kept so stored reservations and
884 /// ledger lines parse; never issued.
Mission control counts people's direct pushes to the default branch885 Agent,
886 /// Checks on a pull request.
887 Check,
888 /// A workflow job.
889 Workflow,
890 /// The merge queue's checks.
891 Queue,
892 /// A deployment's build.
893 Deploy,
The contracts no longer describe g1t's own agents, and workspaces can keep their AI providers. Every consumer had already stopped using them, so the TypeScript and Rust contracts drop the workspace-agent, ability, look, skill-library, context, runner-agent and mention modules, the chat and docs RPCs agents posted and read through, the folio agent methods, the agent_waiting notification, agent.asked and memory.changed events, AI credit, token and gateway billing types, model routes and sessions, team agents, agent tokens, plan, review, message and confidence types, command rules, cost caps and confidence rules. The agents:run and models:* scopes are no longer offered by any preset, OAuth default or permission form, but a stored token or grant that names them still reads; and the removed operations are gone from the scope table, so the API's check that every operation has exactly one scope is strict again. What stored data needs in order to parse (old run and credential kinds, an agent team lead, retired rules and webhook events, old guardrail and integration settings) still parses, and a run's token is still PrincipalKind::Agent, which now means a run's token and the @g1t rows written before. The customize, marketplace, skills and claude-plugin contracts stay only until the mobile app drops its Customize screens.894 /// Semantic search embeddings, retired: kept so stored reservations
895 /// parse; never issued.
Mission control counts people's direct pushes to the default branch896 Embedding,
897}
898
899impl ComputeKind {
900 pub fn as_str(self) -> &'static str {
901 match self {
902 ComputeKind::Agent => "agent",
903 ComputeKind::Check => "check",
904 ComputeKind::Workflow => "workflow",
905 ComputeKind::Queue => "queue",
906 ComputeKind::Deploy => "deploy",
907 ComputeKind::Embedding => "embedding",
908 }
909 }
910
911 /// Whether g1t's open-source pool may pay for it on a public
912 /// repository: checks, workflows and the merge queue only.
913 pub fn open_source_pool(self) -> bool {
914 matches!(self, ComputeKind::Check | ComputeKind::Workflow | ComputeKind::Queue)
915 }
916}
917
918/// Who pays first for reserved work. What the first source cannot cover
919/// falls to the next, in this order.
920#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
921#[serde(rename_all = "snake_case")]
922pub enum PaidBy {
923 /// The plan's included usage this month.
924 Credit,
925 /// The workspace's one-time trial credit.
926 Trial,
927 /// g1t's open-source pool.
928 Oss,
929 /// Charged to the workspace, at cost plus the margin.
930 OnDemand,
931}
932
933/// `entitlements`: what a workspace may do now, for the services that
934/// start compute and the pages that show it. Takes `EntitlementsArgs`;
935/// returns `Entitlements`. No viewer: callers decide who sees it.
936#[derive(Debug, Serialize, Deserialize)]
937pub struct EntitlementsArgs {
938 pub workspace: String,
939}
940
941/// `audit_retention`: how many days of audit log each workspace keeps, for
942/// the events service's daily purge. Takes `AuditRetentionArgs`; returns
943/// `Vec<AuditRetention>`, one for each workspace asked about.
944#[derive(Debug, Serialize, Deserialize)]
945pub struct AuditRetentionArgs {
946 pub workspaces: Vec<String>,
947}
948
949#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
950pub struct AuditRetention {
951 pub workspace: String,
952 pub days: u32,
953}
954
955#[derive(Clone, Debug, Serialize, Deserialize)]
956#[serde(rename_all = "camelCase")]
957pub struct Entitlements {
958 pub workspace: String,
959 pub plan: PlanKind,
960 /// May start sandboxes, models, deployments and semantic search at all:
961 /// paid, internal and enterprise workspaces, or a free one with trial
962 /// credit left. A free workspace may still use the open-source pool
963 /// for checks, workflows and the merge queue on public repositories
964 /// after a card check; `reserve` decides that per start.
965 pub compute: bool,
966 /// The one-time trial credit left; 0 if none was granted or it is used.
967 pub trial_micros_left: i64,
968 /// A card check has been done. The trial and the open-source pool need
969 /// it.
970 pub trial_verified: bool,
971 /// A paid workspace still in its first billing cycle.
972 pub first_month: bool,
973 /// Agents at once: 2 in the first month or on the trial, 10 after;
974 /// staff can override it.
975 pub max_concurrent_agents: u32,
976 /// The longest one run may take: 60 minutes in the first month or on
977 /// the trial; otherwise the guardrails' own caps (`MAX_MINUTES`).
978 pub max_run_minutes: u32,
979 /// One run's spend cap (`RUN_CAP_MICROS`, $2 by default); staff can
980 /// override it.
981 pub run_cap_micros: i64,
982 /// What agents may spend on one issue in all (`ISSUE_CAP_MICROS`, $10
983 /// by default); the owners can set it (`set_caps`), and staff override.
984 pub issue_cap_micros: i64,
985 /// Where on-demand work stops: g1t's ceiling on usage not yet paid
986 /// for. `UNLIMITED_MICROS` for g1t's own workspaces; 0 for a free one,
987 /// which has no on-demand usage.
988 pub ceiling_micros: i64,
989 /// Usage not yet paid for this month, with prepayment taken off.
990 pub exposure_micros: i64,
991 /// Why new compute is paused, for the owner: the limit is reached, a
992 /// spend spike is waiting for an owner to confirm it, or g1t staff put
993 /// a hold on it. None when it is not.
994 pub paused: Option<String>,
Merge main into rm-agents: mirroring removal, open signups, free-tier limits, the g1t CLI and runner fixes, with the agent removal kept. The CLI's table of operations is regenerated from the API without the agent, customize and AI credit operations; no CLI command used them.995 /// g1t staff put a hold on the account (sudo, Allowances): besides new
996 /// compute, nothing new is set up for it, such as a self-hosted runner.
997 #[serde(default)]
998 pub held: bool,
Mission control counts people's direct pushes to the default branch999 // What the workspace's plan gives it, for its pages.
1000 /// What open reservations hold now.
1001 #[serde(default)]
1002 pub held_micros: i64,
1003 /// Paid in advance and not used yet.
1004 #[serde(default)]
1005 pub prepaid_micros: i64,
1006 /// The plan's included usage each month, and what of it is used.
1007 #[serde(default)]
1008 pub included_micros: i64,
1009 #[serde(default)]
1010 pub included_used_micros: i64,
1011 /// How far back the audit log can be read and exported, and what is
1012 /// kept: the plan's days, or what g1t staff set for the account.
1013 pub audit_retention_days: u32,
1014 /// Whether `audit_retention_days` is what staff set for the account
1015 /// rather than the plan's.
1016 #[serde(default)]
1017 pub audit_retention_custom: bool,
1018 /// Private repository storage that is free for every workspace: past
1019 /// it, the plan pays for it and a free workspace's pushes stop.
1020 pub free_private_storage_bytes: i64,
1021 /// The last daily measure of the workspace's private repositories.
1022 pub private_storage_bytes: i64,
1023 /// On a paid plan (not Free): storage past the free amounts below is
1024 /// charged, so nothing is refused for it.
1025 #[serde(default)]
1026 pub has_plan: bool,
1027 /// Package storage free for every workspace, public and private: past
1028 /// it, the plan pays for it and a free workspace's pushes are refused.
1029 #[serde(default)]
1030 pub package_public_free_bytes: i64,
1031 #[serde(default)]
1032 pub package_private_free_bytes: i64,
1033 /// What g1t's open-source pool paid for the workspace this month.
1034 pub oss_paid_micros: i64,
1035 /// Deploy build time this month, every second of it metered.
1036 #[serde(default)]
1037 pub build_seconds_used: u32,
1038 /// Git operations this month, and how many are free for every
1039 /// workspace (past it: metered on the plan, slowed when free).
1040 #[serde(default)]
1041 pub git_operations: u64,
1042 #[serde(default)]
1043 pub git_operations_included: u64,
1044 /// The smallest amount a card is charged when a month closes.
1045 pub min_charge_micros: i64,
1046 /// A spend spike waiting for an owner, or decided.
1047 #[serde(default)]
1048 pub spike: Option<Spike>,
1049 /// Where usage stands against what is included and the limits, from 50%.
1050 #[serde(default)]
1051 pub alerts: Vec<UsageAlert>,
1052}
1053
1054/// One level reached: 50, 75, 90 or 100 percent of something.
1055#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1056#[serde(rename_all = "camelCase")]
1057pub struct UsageAlert {
1058 /// `included` (the plan's included usage), `spend_limit` (the owners'
1059 /// own limit) or `ceiling` (g1t's, on usage not yet paid for).
1060 pub meter: String,
1061 pub level: u32,
1062 pub used_micros: i64,
1063 pub limit_micros: i64,
1064 pub message: String,
1065}
1066
1067/// An hour's spend well above the workspace's usual pace: new compute
1068/// waits until an owner says to keep going.
1069#[derive(Clone, Debug, Serialize, Deserialize)]
1070#[serde(rename_all = "camelCase")]
1071pub struct Spike {
1072 pub id: String,
1073 /// `open` (waiting for an owner), `continued` (an owner said keep
1074 /// going) or `stopped` (an owner said stop).
1075 pub status: String,
1076 /// The hour's spend when it was found, and the usual hour's.
1077 pub hour_micros: i64,
1078 pub average_micros: i64,
1079 pub detected_at: String,
1080 #[serde(default)]
1081 pub decided_by: Option<String>,
1082 #[serde(default)]
1083 pub decided_at: Option<String>,
1084 /// While continued: until when, unless spend doubles again first.
1085 #[serde(default)]
1086 pub until: Option<String>,
1087}
1088
1089/// `reserve`: holds an estimate of a start's cost before the work starts.
1090/// Returns `Outcome<Reservation>`, or a failure whose code says why not:
1091///
1092/// - `paused`: a spend spike waiting for an owner, or a hold.
1093/// - `limit`: the spend limit or g1t's ceiling would be passed.
1094/// - `not_paid`: no plan, and nothing else pays for this kind of work (or
1095/// no card check yet).
1096/// - `trial_used`: the one-time trial is spent.
1097/// - `oss_pool_empty`: the open-source pool, or the repository's share of
1098/// it, is spent this month.
1099///
1100/// The message says exactly what to do, with the page to do it on (such as
1101/// `/acme/-/billing`).
1102#[derive(Debug, Serialize, Deserialize)]
1103#[serde(rename_all = "camelCase")]
1104pub struct ReserveArgs {
1105 pub workspace: String,
1106 pub repo: RepoPath,
1107 /// Whether the repository is public: the open-source pool pays only for
1108 /// public repositories' checks, workflows and merge queue.
1109 pub public: bool,
1110 pub kind: ComputeKind,
1111 /// The most the work is expected to cost g1t, before the margin, in
1112 /// millionths of a dollar (billing adds the margin, as it does to every
The contracts no longer describe g1t's own agents, and workspaces can keep their AI providers. Every consumer had already stopped using them, so the TypeScript and Rust contracts drop the workspace-agent, ability, look, skill-library, context, runner-agent and mention modules, the chat and docs RPCs agents posted and read through, the folio agent methods, the agent_waiting notification, agent.asked and memory.changed events, AI credit, token and gateway billing types, model routes and sessions, team agents, agent tokens, plan, review, message and confidence types, command rules, cost caps and confidence rules. The agents:run and models:* scopes are no longer offered by any preset, OAuth default or permission form, but a stored token or grant that names them still reads; and the removed operations are gone from the scope table, so the API's check that every operation has exactly one scope is strict again. What stored data needs in order to parse (old run and credential kinds, an agent team lead, retired rules and webhook events, old guardrail and integration settings) still parses, and a run's token is still PrincipalKind::Agent, which now means a run's token and the @g1t rows written before. The customize, marketplace, skills and claude-plugin contracts stay only until the mobile app drops its Customize screens.1113 /// charge): its sandbox for its whole time cap.
Mission control counts people's direct pushes to the default branch1114 #[serde(alias = "estimate_micros")]
1115 pub estimate_micros: i64,
1116}
1117
1118#[derive(Clone, Debug, Serialize, Deserialize)]
1119#[serde(rename_all = "camelCase")]
1120pub struct Reservation {
1121 pub id: String,
1122 pub paid_by: PaidBy,
1123 /// What is held, at cost; less than the estimate when a free
1124 /// workspace's last bit of trial credit is all there is.
1125 #[serde(default)]
1126 pub held_micros: i64,
1127 /// RFC 3339: when the hold lapses if never settled.
1128 #[serde(default)]
1129 pub expires_at: String,
1130}
1131
1132/// `settle`: releases a reservation's hold with what the work cost. The
1133/// charge goes on the ledger the usual way. Safe to repeat. Returns
1134/// `Outcome<bool>`: false if it was settled or had lapsed before.
1135#[derive(Debug, Serialize, Deserialize)]
1136#[serde(rename_all = "camelCase")]
1137pub struct SettleArgs {
1138 #[serde(alias = "reservation_id")]
1139 pub reservation_id: String,
1140 /// What the work cost g1t, before the margin.
1141 #[serde(alias = "actual_micros")]
1142 pub actual_micros: i64,
1143}
1144
1145// --- Card checks, the plan, prepayment -------------------------------------
1146
1147/// `card_check`: starts Stripe's page to save and verify a card: a setup
1148/// with 3-D Secure where the card supports it, which the card's bank sees
1149/// as a $0 or $1 authorization that is never charged. The trial and the
1150/// open-source pool need it, and it is the card the plan uses. Owners only.
1151/// Returns `Outcome<Checkout>`; the page's id comes back to `return_url` as
1152/// `session`, for `confirm_card_check`.
1153#[derive(Debug, Serialize, Deserialize)]
1154#[serde(rename_all = "camelCase")]
1155pub struct CardCheckArgs {
1156 pub actor: User,
1157 pub workspace: String,
1158 #[serde(alias = "return_url")]
1159 pub return_url: String,
1160}
1161
1162/// `confirm_card_check`: records the check once Stripe says the card was
1163/// verified, and grants the trial if the month's pool has room and the card
1164/// has not had one before. Safe to repeat. Returns `Outcome<Entitlements>`.
1165#[derive(Debug, Serialize, Deserialize)]
1166pub struct ConfirmCardCheckArgs {
1167 pub workspace: String,
1168 pub viewer: Viewer,
1169 pub session: String,
1170}
1171
1172// --- Limits: raising them, and spikes ---------------------------------------
1173
1174/// A request to g1t: a higher limit, or help with usage that went past
1175/// what was meant.
1176#[derive(Clone, Debug, Serialize, Deserialize)]
1177#[serde(rename_all = "camelCase")]
1178pub struct LimitRequest {
1179 pub id: String,
1180 pub workspace: String,
1181 /// `limit` (raise my limit) or `overage` (spent more than meant to).
1182 pub kind: String,
1183 /// The limit asked for; for an overage, what they think went wrong.
1184 pub amount_micros: i64,
1185 pub reason: String,
1186 pub expected_monthly_micros: i64,
1187 /// `open`, `approved` or `declined`.
1188 pub status: String,
1189 /// What was approved, which may differ from what was asked.
1190 #[serde(default)]
1191 pub decided_micros: Option<i64>,
1192 #[serde(default)]
1193 pub decided_by: Option<String>,
1194 /// The answer, as the owner sees it.
1195 #[serde(default)]
1196 pub answer: Option<String>,
1197 pub created_by: String,
1198 pub created_at: String,
1199 #[serde(default)]
1200 pub decided_at: Option<String>,
1201}
1202
1203/// `request_limit`: an owner asks g1t for more, or for help with usage past
1204/// what they meant. Answered within one business day, in the app and by
1205/// email. Owners only. Returns `Outcome<LimitRequest>`.
1206#[derive(Debug, Serialize, Deserialize)]
1207#[serde(rename_all = "camelCase")]
1208pub struct RequestLimitArgs {
1209 pub actor: User,
1210 pub workspace: String,
1211 /// `limit` or `overage`.
1212 pub kind: String,
1213 #[serde(alias = "amount_micros")]
1214 pub amount_micros: i64,
1215 pub reason: String,
1216 #[serde(default, alias = "expected_monthly_micros")]
1217 pub expected_monthly_micros: i64,
1218}
1219
1220/// `limit_requests`: a workspace's requests, newest first. Members only.
1221/// Returns `Outcome<Vec<LimitRequest>>`.
1222#[derive(Debug, Serialize, Deserialize)]
1223pub struct LimitRequestsArgs {
1224 pub workspace: String,
1225 pub viewer: Viewer,
1226}
1227
1228/// `confirm_spike`: an owner's answer to a spend spike. Keep going lifts the
1229/// pause for 24 hours, or until the hour's spend doubles again; stop keeps
1230/// new compute paused until an owner says to keep going. Owners only.
1231/// Returns `Outcome<Entitlements>`.
1232#[derive(Debug, Serialize, Deserialize)]
1233#[serde(rename_all = "camelCase")]
1234pub struct ConfirmSpikeArgs {
1235 pub actor: User,
1236 pub workspace: String,
1237 #[serde(alias = "keep_going")]
1238 pub keep_going: bool,
1239}
1240
1241/// `set_caps`: the owners' own caps on agents: one run's spend ($0.10 to
1242/// $100) and what the agents on one issue may spend in all ($1 to $1,000).
1243/// None goes back to the default ($2 and $10). A cap g1t staff set for the
1244/// account wins over both. Owners only. Returns `Outcome<Entitlements>`.
1245#[derive(Debug, Serialize, Deserialize)]
1246#[serde(rename_all = "camelCase")]
1247pub struct SetCapsArgs {
1248 pub actor: User,
1249 pub workspace: String,
1250 #[serde(default, alias = "run_cap_micros")]
1251 pub run_cap_micros: Option<i64>,
1252 #[serde(default, alias = "issue_cap_micros")]
1253 pub issue_cap_micros: Option<i64>,
1254}
1255
1256/// What staff see beside a request: the workspace's history with g1t.
1257#[derive(Clone, Debug, Default, Serialize, Deserialize)]
1258#[serde(rename_all = "camelCase")]
1259pub struct WorkspaceHistory {
1260 pub plan: Option<PlanKind>,
1261 /// The last six months, oldest first.
1262 pub months: Vec<MonthFigures>,
1263 /// Live payments that have cleared, and how many.
1264 pub paid_cleared_micros: i64,
1265 pub payments: u32,
1266 pub disputes: u32,
1267 pub declines: u32,
1268 /// The first time the workspace appears in billing, RFC 3339.
1269 pub first_seen: Option<String>,
1270 pub ceiling_micros: Option<i64>,
1271 pub max_ceiling_micros: Option<i64>,
1272 pub spend_limit_micros: Option<i64>,
1273 /// Recent velocity: the last hour, the usual hour over the last week,
1274 /// and the last 24 hours, at price.
1275 pub last_hour_micros: i64,
1276 pub average_hour_micros: i64,
1277 pub last_day_micros: i64,
1278}
1279
1280#[derive(Clone, Debug, Serialize, Deserialize)]
1281#[serde(rename_all = "camelCase")]
1282pub struct LimitRequestReview {
1283 pub request: LimitRequest,
1284 pub history: WorkspaceHistory,
1285}
1286
1287/// `admin_limit_requests`: requests for staff, oldest open first. Returns
1288/// `Vec<LimitRequestReview>`.
1289#[derive(Debug, Default, Serialize, Deserialize)]
1290pub struct AdminLimitRequestsArgs {
1291 /// `open` (the default), `approved`, `declined` or `all`.
1292 #[serde(default)]
1293 pub status: Option<String>,
1294}
1295
1296/// `admin_decide_limit_request`: approve (at the amount asked, or
1297/// `amount_micros`) or decline. The owner is told in the app and by email.
1298/// Recorded with who and why. Returns `Outcome<LimitRequest>`.
1299#[derive(Debug, Serialize, Deserialize)]
1300pub struct AdminDecideLimitRequestArgs {
1301 pub id: String,
1302 /// `approve` or `decline`.
1303 pub decision: String,
1304 #[serde(default)]
1305 pub amount_micros: Option<i64>,
1306 /// What the owner is told, beside the decision.
1307 #[serde(default)]
1308 pub note: String,
1309 pub by: String,
1310}
1311
1312/// `admin_record_payment`: money that reached g1t outside the card pages,
1313/// such as a bank transfer, entered as a payment (it raises the limit like
1314/// one). Recorded with who and the transfer's reference. Returns
1315/// `Outcome<LedgerEntry>`.
1316#[derive(Debug, Serialize, Deserialize)]
1317pub struct AdminRecordPaymentArgs {
1318 pub workspace: String,
1319 pub amount_micros: i64,
1320 /// The bank's reference for the transfer, or Stripe's payment id.
1321 pub reference: String,
1322 pub note: String,
1323 pub by: String,
1324}
1325
1326// --- Overages and goodwill (sudo) --------------------------------------------
1327
1328/// What a one-time goodwill credit would come to: g1t's margin on the
1329/// overage, always, plus as much of its underlying cost as the cap allows.
1330#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
1331#[serde(rename_all = "camelCase")]
1332pub struct Goodwill {
1333 /// This month's charges above the workspace's typical month.
1334 pub overage_micros: i64,
1335 /// The part of the overage that is g1t's margin.
1336 pub margin_micros: i64,
1337 /// The part that is what g1t paid its providers.
1338 pub cost_micros: i64,
1339 /// The one-click credit: the margin plus the cost up to the cap.
1340 pub credit_micros: i64,
1341 /// Of the credit, the real cost g1t absorbs.
1342 pub absorbed_micros: i64,
1343}
1344
1345/// A workspace whose month went well past its usual, or hit a spike.
1346#[derive(Clone, Debug, Serialize, Deserialize)]
1347#[serde(rename_all = "camelCase")]
1348pub struct Overage {
1349 pub workspace: String,
1350 pub plan: PlanKind,
1351 /// The median of its last three months' charges.
1352 pub typical_month_micros: i64,
1353 pub this_month_micros: i64,
1354 /// What this month cost g1t, and what g1t keeps of it.
1355 pub cost_micros: i64,
1356 pub margin_micros: i64,
1357 /// A spike this month, if there was one.
1358 pub spike: Option<Spike>,
1359 /// The runs that cost the most this month.
1360 pub top_entries: Vec<LedgerEntry>,
1361 pub goodwill: Goodwill,
1362 /// False when a goodwill credit was given in the last 12 months.
1363 pub goodwill_available: bool,
1364 pub last_goodwill_at: Option<String>,
1365 /// An open overage request from the owner, if there is one.
1366 pub request: Option<LimitRequest>,
1367}
1368
1369/// `admin_overages`: the Overages queue. Returns `Vec<Overage>`.
1370#[derive(Debug, Default, Serialize, Deserialize)]
1371pub struct AdminOveragesArgs {}
1372
1373/// `admin_goodwill`: credits a workspace for accidental usage. With no
1374/// amount, the one-click credit (`Goodwill::credit_micros`), once per
1375/// workspace in 12 months. A larger amount, or a second within 12 months,
1376/// needs a typed reason. It shows on the statement as "Credit from g1t:
1377/// accidental usage on <date>". Returns `Outcome<LedgerEntry>`.
1378#[derive(Debug, Serialize, Deserialize)]
1379pub struct AdminGoodwillArgs {
1380 pub workspace: String,
1381 #[serde(default)]
1382 pub amount_micros: Option<i64>,
1383 /// Why, typed by staff; needed past the one-click credit.
1384 #[serde(default)]
1385 pub reason: String,
1386 /// The day the accidental usage happened, `YYYY-MM-DD`; today if absent.
1387 #[serde(default)]
1388 pub day: Option<String>,
1389 pub by: String,
1390}
1391
1392/// One workspace's recent pace, for sudo's velocity view.
1393#[derive(Clone, Debug, Serialize, Deserialize)]
1394#[serde(rename_all = "camelCase")]
1395pub struct Velocity {
1396 pub workspace: String,
1397 pub plan: PlanKind,
1398 pub last_hour_micros: i64,
1399 pub average_hour_micros: i64,
1400 pub last_day_micros: i64,
1401 pub this_month_micros: i64,
1402 /// The last hour over the usual hour; 0 with no history.
1403 pub ratio: f64,
1404 pub spike: Option<Spike>,
1405 pub first_seen: Option<String>,
1406}
1407
1408/// `admin_velocity`: workspaces spending in the last day, fastest first.
1409/// Returns `Vec<Velocity>`.
1410#[derive(Debug, Default, Serialize, Deserialize)]
1411pub struct AdminVelocityArgs {}
1412
1413#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1414#[serde(rename_all = "snake_case")]
1415pub enum AccountKind {
1416 Workspace,
1417 Enterprise,
1418}
1419
1420/// How an account is charged. Standard unless g1t set otherwise in sudo.
1421#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1422#[serde(rename_all = "camelCase")]
1423pub struct Terms {
1424 pub kind: TermsKind,
1425 /// Off every usage charge, in percent. Custom terms only.
1426 #[serde(default)]
1427 pub discount_percent: u32,
1428 /// A ceiling on unpaid usage that replaces the one trust would give.
1429 #[serde(default)]
1430 pub ceiling_micros: Option<i64>,
1431 /// Why, for whoever looks next.
1432 #[serde(default)]
1433 pub note: String,
1434 /// When the terms end and the account goes back to standard.
1435 #[serde(default)]
1436 pub until: Option<String>,
1437 #[serde(default)]
1438 pub set_by: Option<String>,
1439 #[serde(default)]
1440 pub set_at: Option<String>,
1441}
1442
1443impl Terms {
1444 pub fn standard() -> Self {
1445 Terms {
1446 kind: TermsKind::Standard,
1447 discount_percent: 0,
1448 ceiling_micros: None,
1449 note: String::new(),
1450 until: None,
1451 set_by: None,
1452 set_at: None,
1453 }
1454 }
1455
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging1456 /// The discount in percent, 0 to 100. Terms from before discounts
1457 /// replaced "comped" read as 100%.
1458 pub fn percent_off(&self) -> u32 {
1459 match self.kind {
1460 TermsKind::Comped => 100,
1461 TermsKind::Custom => self.discount_percent.min(100),
1462 TermsKind::Standard => 0,
1463 }
1464 }
1465
1466 /// A 100% discount: nothing is charged, usage is recorded at its price
1467 /// and discounted in full. g1t's own workspaces and partners. Paid
1468 /// features are on without a plan, and g1t's own spend on it is held to
1469 /// a monthly budget (the terms' ceiling, at cost).
1470 pub fn full_discount(&self) -> bool {
1471 self.percent_off() >= 100
1472 }
1473
Mission control counts people's direct pushes to the default branch1474 /// What a charge becomes under these terms.
1475 pub fn apply(&self, charge_micros: i64) -> i64 {
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging1476 charge_micros * i64::from(100 - self.percent_off()) / 100
Mission control counts people's direct pushes to the default branch1477 }
Merge branch 'worktree-agent-a633ac0f7f66d419d'1478
1479 /// What a charge at cost plus the margin becomes under these terms, and
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging1480 /// what the discount took off it (`ledger.discount_micros`), so the
1481 /// statement shows the usage at its price and the discount beside it,
1482 /// and a discount below cost plus the margin is counted as given, never
1483 /// lost. A 100% discount takes it all.
Merge branch 'worktree-agent-a633ac0f7f66d419d'1484 pub fn discounted(&self, charge_micros: i64) -> (i64, i64) {
1485 let charged = self.apply(charge_micros);
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging1486 (charged, (charge_micros - charged).max(0))
1487 }
1488
1489 /// How the statement and sudo name the terms: `100% discount`, `30% off`.
1490 pub fn discount_label(&self) -> Option<String> {
1491 match self.percent_off() {
1492 0 => None,
1493 100 => Some("100% discount".to_owned()),
1494 percent => Some(format!("{percent}% off")),
Merge branch 'worktree-agent-a633ac0f7f66d419d'1495 }
1496 }
Mission control counts people's direct pushes to the default branch1497}
1498
1499#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1500#[serde(rename_all = "snake_case")]
1501pub enum TermsKind {
1502 /// Prices as published, limits by trust.
1503 Standard,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging1504 /// Before discounts: what a 100% discount is now. Read as one
1505 /// (`Terms::percent_off`); billing never writes it (migration 0039).
Mission control counts people's direct pushes to the default branch1506 Comped,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging1507 /// A discount (up to 100%), a ceiling, or both.
Mission control counts people's direct pushes to the default branch1508 Custom,
1509}
1510
1511/// `stripe_webhook`: an event from Stripe, as the API received it: the raw
1512/// body and its `Stripe-Signature` header. Billing checks the signature
1513/// against the secret of the endpoint it registered, and handles each
1514/// event once. Returns `Outcome<bool>`: false for one already handled.
1515#[derive(Debug, Serialize, Deserialize)]
1516pub struct StripeWebhookArgs {
1517 pub payload: String,
1518 pub signature: String,
1519}
1520
1521/// `admin_stripe`: where billing stands with Stripe. Staff only. Returns
1522/// `StripeStatus`. With `fix: true`, first enables the destination at
1523/// billing's address and gives it the events billing needs.
1524#[derive(Debug, Default, Serialize, Deserialize)]
1525pub struct AdminStripeArgs {
1526 #[serde(default)]
1527 pub fix: bool,
1528 #[serde(default)]
1529 pub by: Option<String>,
1530}
1531
1532#[derive(Clone, Debug, Serialize, Deserialize)]
1533#[serde(rename_all = "camelCase")]
1534pub struct StripeStatus {
1535 /// `test` or `live`, from the key; `off` without one.
1536 pub mode: String,
1537 /// Whether `STRIPE_WEBHOOK_SECRET` is set, so events can be checked.
1538 pub secret_set: bool,
1539 /// The destination at billing's address in Stripe, as Stripe has it.
1540 pub webhook: Option<StripeWebhook>,
1541 /// Events billing handles that the destination does not send.
1542 pub missing_events: Vec<String>,
1543 /// The latest events handled, newest first.
1544 pub recent_events: Vec<StripeEventSummary>,
1545 /// What went wrong reading or fixing the destination, if it did.
1546 pub error: Option<String>,
1547}
1548
1549#[derive(Clone, Debug, Serialize, Deserialize)]
1550#[serde(rename_all = "camelCase")]
1551pub struct StripeWebhook {
1552 pub url: String,
1553 pub endpoint_id: String,
1554 /// `enabled` or `disabled`.
1555 pub status: String,
1556 pub events: Vec<String>,
1557 pub created_at: String,
1558}
1559
1560#[derive(Clone, Debug, Serialize, Deserialize)]
1561#[serde(rename_all = "camelCase")]
1562pub struct StripeEventSummary {
1563 pub id: String,
1564 pub kind: String,
1565 pub outcome: String,
1566 pub received_at: String,
1567}
1568
1569/// `admin_enterprise_billing`: where an enterprise's invoices go. Creates
1570/// or updates its Stripe customer. Returns `Outcome<BillingAccount>`.
1571#[derive(Debug, Serialize, Deserialize)]
1572pub struct AdminEnterpriseBillingArgs {
1573 pub id: String,
1574 pub email: String,
1575 pub by: String,
1576}
1577
Merge Stripe Tax, the card fee on card payments, and one free workspace per person1578/// `admin_enterprise_address`: the enterprise's billing address and tax ID,
1579/// saved on its Stripe customer (made by `admin_enterprise_billing`).
1580/// Stripe Tax works its invoices' tax out from the address; an invoice is
1581/// not sent without one. Returns `Outcome<bool>`.
1582#[derive(Debug, Serialize, Deserialize)]
1583#[serde(rename_all = "camelCase")]
1584pub struct AdminEnterpriseAddressArgs {
1585 pub id: String,
1586 pub address: PostalAddress,
1587 #[serde(default, alias = "tax_id_type")]
1588 pub tax_id_type: Option<String>,
1589 #[serde(default, alias = "tax_id")]
1590 pub tax_id: Option<String>,
1591 pub by: String,
1592}
1593
Mission control counts people's direct pushes to the default branch1594/// `admin_invoice_enterprise`: sends an enterprise its invoice now, for
1595/// what its workspaces owe, rather than waiting for the month to close.
1596/// Returns `Outcome<EnterpriseInvoice>`.
1597#[derive(Debug, Serialize, Deserialize)]
1598pub struct AdminInvoiceEnterpriseArgs {
1599 pub id: String,
1600 pub by: String,
1601}
1602
1603/// An enterprise's invoice: one line per workspace, paid on Stripe.
1604#[derive(Clone, Debug, Serialize, Deserialize)]
1605#[serde(rename_all = "camelCase")]
1606pub struct EnterpriseInvoice {
1607 pub invoice_id: String,
1608 /// Stripe's page for it, where it is paid.
1609 pub hosted_url: Option<String>,
1610 pub amount_micros: i64,
1611 /// `open`, `paid`, `overdue` or `void`.
1612 pub status: String,
1613 pub period: String,
1614 pub lines: Vec<InvoiceLine>,
1615 pub created_at: String,
1616}
1617
1618#[derive(Clone, Debug, Serialize, Deserialize)]
1619#[serde(rename_all = "camelCase")]
1620pub struct InvoiceLine {
1621 pub workspace: String,
1622 pub amount_micros: i64,
1623}
1624
1625/// A workspace's invoice from g1t: one per month, and one each time it is
1626/// charged near its limit. Itemised, charged to the card on file, and kept
1627/// in Stripe's billing page with its PDF.
1628#[derive(Clone, Debug, Serialize, Deserialize)]
1629#[serde(rename_all = "camelCase")]
1630pub struct WorkspaceInvoice {
1631 pub invoice_id: String,
1632 pub workspace: String,
1633 /// `month` (2026-10) or `threshold`.
1634 pub reason: String,
1635 pub period: String,
1636 pub amount_micros: i64,
1637 /// `paid`, `open`, `failed` or `void`.
1638 pub status: String,
1639 pub hosted_url: Option<String>,
1640 pub pdf_url: Option<String>,
1641 pub lines: Vec<InvoiceItem>,
1642 pub created_at: String,
Merge Stripe Tax, the card fee on card payments, and one free workspace per person1643 /// The card processing fee on top of `amount_micros`, when the invoice
1644 /// is charged to a card; never part of the usage it pays for.
1645 #[serde(default)]
1646 pub fee_micros: i64,
1647 /// The tax Stripe added on top, once it is known (after paying).
1648 #[serde(default)]
1649 pub tax_micros: i64,
Mission control counts people's direct pushes to the default branch1650}
1651
1652#[derive(Clone, Debug, Serialize, Deserialize)]
1653#[serde(rename_all = "camelCase")]
1654pub struct InvoiceItem {
1655 pub description: String,
1656 pub amount_micros: i64,
1657}
1658
1659/// `invoices`: a workspace's invoices from g1t, newest first. Members
1660/// only. Returns `Outcome<Vec<WorkspaceInvoice>>`.
1661#[derive(Debug, Serialize, Deserialize)]
1662pub struct InvoicesArgs {
1663 pub workspace: String,
1664 pub viewer: Viewer,
1665}
1666
1667/// `admin_workspace_invoices`: the same, for staff. Returns
1668/// `Vec<WorkspaceInvoice>`.
1669#[derive(Debug, Serialize, Deserialize)]
1670pub struct AdminWorkspaceInvoicesArgs {
1671 pub workspace: String,
1672}
1673
1674/// `statement`: a month of a workspace's ledger, grouped by day (or by
1675/// project) with a line per kind of charge. Members only. Returns
1676/// `Outcome<Statement>`.
1677#[derive(Debug, Serialize, Deserialize)]
1678pub struct StatementArgs {
1679 pub workspace: String,
1680 pub viewer: Viewer,
1681 /// YYYY-MM; this month when absent.
1682 #[serde(default)]
1683 pub month: Option<String>,
1684 /// `day` (the default) or `project`.
1685 #[serde(default)]
1686 pub group: Option<String>,
1687}
1688
1689#[derive(Clone, Debug, Serialize, Deserialize)]
1690#[serde(rename_all = "camelCase")]
1691pub struct Statement {
1692 pub month: String,
1693 /// Months with any entries, newest first.
1694 pub months: Vec<String>,
1695 pub groups: Vec<StatementGroup>,
1696 pub totals: StatementTotals,
1697}
1698
1699#[derive(Clone, Debug, Serialize, Deserialize)]
1700#[serde(rename_all = "camelCase")]
1701pub struct StatementGroup {
1702 /// The day (YYYY-MM-DD) or the project (`owner/name`, or empty).
1703 pub key: String,
1704 pub label: String,
1705 pub lines: Vec<StatementLine>,
1706 /// What the group's charges come to.
1707 pub charged_micros: i64,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging1708 /// Its usage at price, and what the discount took off it.
1709 #[serde(default)]
1710 pub price_micros: i64,
1711 #[serde(default)]
1712 pub discount_micros: i64,
Mission control counts people's direct pushes to the default branch1713}
1714
1715#[derive(Clone, Debug, Serialize, Deserialize)]
1716#[serde(rename_all = "camelCase")]
1717pub struct StatementLine {
1718 /// Agent runs, Sandbox time, Deployments, Payments, Credits from g1t,
1719 /// Refunds, and, for older entries, Runs on your own model provider.
1720 pub kind: String,
1721 pub count: u32,
1722 /// Charges positive; money in (payments, credits) negative.
1723 pub charged_micros: i64,
1724 pub cost_micros: i64,
1725 /// Of the usage on the line, what was paid for before it was charged:
1726 /// by the plan's included usage, the trial credit, g1t's open-source
1727 /// pool, or g1t itself. Not in `charged_micros`.
1728 #[serde(default)]
1729 pub covered_micros: i64,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging1730 /// Usage at its price: charged, plus what paid for it and what the
1731 /// discount took off. Zero for money in.
1732 #[serde(default)]
1733 pub price_micros: i64,
1734 /// What the account's discount took off the line's price.
1735 #[serde(default)]
1736 pub discount_micros: i64,
Merge Stripe Tax, the card fee on card payments, and one free workspace per person1737 /// On the `Tax` and `Card processing fees` lines: what was paid with
1738 /// payments on top of what reached the balance (negative for what a
1739 /// refund gave back). Never in `charged_micros` or the balance.
1740 #[serde(default)]
1741 pub passed_micros: i64,
Mission control counts people's direct pushes to the default branch1742}
1743
1744#[derive(Clone, Debug, Serialize, Deserialize)]
1745#[serde(rename_all = "camelCase")]
1746pub struct StatementTotals {
1747 pub charged_micros: i64,
1748 pub paid_micros: i64,
1749 pub cost_micros: i64,
1750 pub entries: u32,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging1751 /// Usage at price, and what the discount took off it: charged is the
1752 /// price less the discount and what paid for it.
1753 #[serde(default)]
1754 pub price_micros: i64,
1755 #[serde(default)]
1756 pub discount_micros: i64,
1757 /// The account's discount now, in percent; absent without one.
1758 #[serde(default)]
1759 pub discount_percent: Option<u32>,
Mission control counts people's direct pushes to the default branch1760 /// What paid for usage before it was charged, one line per source,
1761 /// such as "Paid by g1t's open-source pool".
1762 #[serde(default)]
1763 pub covered: Vec<Covered>,
1764 /// Owed when the month closed but under the minimum charge, so it
1765 /// carries over to the next invoice. Zero when nothing carried.
1766 #[serde(default)]
1767 pub carried_micros: i64,
Merge Stripe Tax, the card fee on card payments, and one free workspace per person1768 /// Tax and card processing fees paid with the month's payments, on top
1769 /// of `paid_micros`.
1770 #[serde(default)]
1771 pub tax_micros: i64,
1772 #[serde(default)]
1773 pub card_fee_micros: i64,
Mission control counts people's direct pushes to the default branch1774}
1775
1776/// One source that paid for usage before it was charged.
1777#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1778#[serde(rename_all = "camelCase")]
1779pub struct Covered {
1780 /// `included`, `trial`, `oss_pool` or `given`.
1781 pub source: String,
1782 /// "Paid by your plan's included usage", "Paid by your trial credit",
1783 /// "Paid by g1t's open-source pool", "Covered by g1t".
1784 pub label: String,
1785 pub micros: i64,
1786}
1787
1788/// `statement_entries`: one statement line's entries, newest first, 50 at
1789/// a time (`before` = the last id seen). Returns `Outcome<Vec<LedgerEntry>>`.
1790#[derive(Debug, Serialize, Deserialize)]
1791pub struct StatementEntriesArgs {
1792 pub workspace: String,
1793 pub viewer: Viewer,
1794 pub month: String,
1795 pub kind: String,
1796 #[serde(default)]
1797 pub day: Option<String>,
1798 #[serde(default)]
1799 pub project: Option<String>,
1800 #[serde(default)]
1801 pub before: Option<String>,
1802}
1803
1804// --- Sales (sudo.g1t.sh) ------------------------------------------------------
1805//
1806// What staff need to know to reach out: who is growing, who is close to
1807// their limit, who was declined, who has become a steady customer. And what
1808// was done about it: a stage, an owner on g1t's side, a next step, notes.
1809
1810/// Why a workspace is worth a look.
1811#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1812#[serde(rename_all = "snake_case")]
1813pub enum SignalKind {
1814 /// At its limit, or its own spend limit: work is stopped.
1815 AtLimit,
1816 /// Past 80% of what is available to it: about to need more.
1817 NearCeiling,
1818 /// Its card was declined or a payment disputed.
1819 Declined,
1820 /// This month is well ahead of last month.
1821 Growing,
1822 /// Became Established: the ceiling now follows its spend.
1823 Established,
1824 /// Paid g1t for the first time.
1825 FirstPayment,
1826 /// Spending enough that custom terms or an enterprise may suit it.
1827 HighSpend,
1828 /// Costs g1t more on Cloudflare than it pays, over 30 days: a pricing
1829 /// gap or abuse to look at (billing's `margin`).
1830 CostOverRevenue,
1831}
1832
1833#[derive(Clone, Debug, Serialize, Deserialize)]
1834#[serde(rename_all = "camelCase")]
1835pub struct Signal {
1836 pub workspace: String,
1837 pub kind: SignalKind,
1838 /// One sentence, with the figures.
1839 pub detail: String,
1840 /// The figure that matters, such as this month's spend.
1841 pub value_micros: i64,
1842 /// Its sales stage, if staff gave it one.
1843 pub stage: Option<String>,
1844 pub owner: Option<String>,
1845 #[serde(default)]
1846 pub next_step: Option<String>,
1847 /// When the next step is due, `YYYY-MM-DD`.
1848 #[serde(default)]
1849 pub next_at: Option<String>,
1850}
1851
1852/// `admin_invoices`: every invoice g1t has sent, workspaces' and
1853/// enterprises', newest first. Returns `Vec<InvoiceSummary>`.
1854#[derive(Debug, Default, Serialize, Deserialize)]
1855pub struct AdminInvoicesArgs {
1856 /// `paid`, `open`, `failed`, `overdue` or `void`.
1857 #[serde(default)]
1858 pub status: Option<String>,
1859 /// YYYY-MM, by when it was sent.
1860 #[serde(default)]
1861 pub month: Option<String>,
1862}
1863
1864#[derive(Clone, Debug, Serialize, Deserialize)]
1865#[serde(rename_all = "camelCase")]
1866pub struct InvoiceSummary {
1867 pub invoice_id: String,
1868 /// `workspace` or `enterprise`.
1869 pub kind: String,
1870 /// The workspace's slug, or the enterprise's account id.
1871 pub account: String,
1872 /// What to call it: the workspace, or the enterprise's name.
1873 pub name: String,
1874 pub reason: String,
1875 pub period: String,
1876 pub amount_micros: i64,
1877 pub status: String,
1878 pub hosted_url: Option<String>,
1879 pub created_at: String,
1880 pub paid_at: Option<String>,
1881}
1882
1883/// `admin_audit`: every change made in sudo, and by Stripe, newest first.
1884/// Returns `Vec<AdminAction>`.
1885#[derive(Debug, Default, Serialize, Deserialize)]
1886pub struct AdminAuditArgs {
1887 #[serde(default)]
1888 pub by: Option<String>,
1889 #[serde(default)]
1890 pub action: Option<String>,
1891 /// Only those before this time, for paging.
1892 #[serde(default)]
1893 pub before: Option<String>,
1894}
1895
1896/// `admin_signals`: every workspace worth reaching out to, most urgent
1897/// first. Returns `Vec<Signal>`.
1898#[derive(Debug, Default, Serialize, Deserialize)]
1899pub struct AdminSignalsArgs {}
1900
1901/// What staff are doing about a workspace.
1902#[derive(Clone, Debug, Serialize, Deserialize)]
1903#[serde(rename_all = "camelCase")]
1904pub struct SalesRecord {
1905 pub workspace: String,
1906 /// `none`, `lead`, `contacted`, `negotiating`, `won`, `lost` or `churn_risk`.
1907 pub stage: String,
1908 /// The staff member looking after it.
1909 pub owner: Option<String>,
1910 pub next_step: Option<String>,
1911 /// RFC 3339 date.
1912 pub next_at: Option<String>,
1913 pub notes: Vec<SalesNote>,
1914 pub updated_at: Option<String>,
1915}
1916
1917#[derive(Clone, Debug, Serialize, Deserialize)]
1918#[serde(rename_all = "camelCase")]
1919pub struct SalesNote {
1920 pub id: String,
1921 pub text: String,
1922 pub by: String,
1923 pub created_at: String,
1924}
1925
1926/// `admin_sales`: a workspace's sales record. Returns `SalesRecord`.
1927#[derive(Debug, Serialize, Deserialize)]
1928pub struct AdminSalesArgs {
1929 pub workspace: String,
1930}
1931
1932/// `admin_set_sales`: its stage, owner and next step. Returns `Outcome<SalesRecord>`.
1933#[derive(Debug, Serialize, Deserialize)]
1934pub struct AdminSetSalesArgs {
1935 pub workspace: String,
1936 pub stage: String,
1937 #[serde(default)]
1938 pub owner: Option<String>,
1939 #[serde(default)]
1940 pub next_step: Option<String>,
1941 #[serde(default)]
1942 pub next_at: Option<String>,
1943 pub by: String,
1944}
1945
1946/// `admin_add_note`. Returns `Outcome<SalesRecord>`.
1947#[derive(Debug, Serialize, Deserialize)]
1948pub struct AdminAddNoteArgs {
1949 pub workspace: String,
1950 pub text: String,
1951 pub by: String,
1952}
1953
1954/// `admin_overview`: the business at a glance. Returns `Overview`.
1955#[derive(Debug, Default, Serialize, Deserialize)]
1956pub struct AdminOverviewArgs {}
1957
1958#[derive(Clone, Debug, Serialize, Deserialize)]
1959#[serde(rename_all = "camelCase")]
1960pub struct Overview {
1961 /// YYYY-MM.
1962 pub month: String,
1963 /// The last six months, oldest first, all workspaces together.
1964 pub months: Vec<MonthFigures>,
1965 /// This month by kind of usage: models, sandbox, deployments, plans.
1966 pub by_kind: Vec<KindFigures>,
1967 pub paying_workspaces: u32,
1968 pub stopped: u32,
1969 pub near_ceiling: u32,
1970 pub declined: u32,
1971 /// Sent and not yet paid, workspaces and enterprises.
1972 pub open_invoices_micros: i64,
1973 /// Follow-ups due today or earlier.
1974 pub follow_ups_due: u32,
1975 /// The capped budgets g1t pays from, this month.
1976 #[serde(default)]
1977 pub pools: Option<Pools>,
1978 /// This month's revenue: usage charged plus the plan's price paid.
1979 #[serde(default)]
1980 pub revenue_micros: i64,
1981 /// Workspaces on the paid plan now, and what their price comes to a
1982 /// month.
1983 #[serde(default)]
1984 pub active_plans: u32,
1985 #[serde(default)]
1986 pub plan_mrr_micros: i64,
1987 /// What g1t gave this month, by source, apart from its margin.
1988 #[serde(default)]
1989 pub given: Vec<GivenFigures>,
1990 /// g1t's own and Flagon's workspaces this month: what their use cost,
1991 /// and why they are not charged.
1992 #[serde(default)]
1993 pub internal: Vec<InternalUse>,
1994 /// Open limit requests, and workspaces in the Overages queue.
1995 #[serde(default)]
1996 pub open_requests: u32,
1997 #[serde(default)]
1998 pub overages: u32,
1999 /// Spend spikes waiting for an owner.
2000 #[serde(default)]
2001 pub open_spikes: u32,
2002}
2003
2004/// What g1t gave this month from one source.
2005#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2006#[serde(rename_all = "camelCase")]
2007pub struct GivenFigures {
2008 /// `internal`, `trial`, `oss_pool`, `goodwill` or `covered`.
2009 pub source: String,
2010 pub label: String,
2011 /// At price, and what it cost g1t.
2012 pub micros: i64,
2013 pub cost_micros: i64,
2014}
2015
2016/// One internal workspace's use this month.
2017#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2018#[serde(rename_all = "camelCase")]
2019pub struct InternalUse {
2020 pub workspace: String,
2021 /// Why it is not charged: its terms' note.
2022 pub reason: String,
2023 pub cost_micros: i64,
2024 pub entries: u32,
2025}
2026
2027/// g1t's capped budgets for free usage, this calendar month (UTC).
2028#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2029#[serde(rename_all = "camelCase")]
2030pub struct Pools {
2031 /// YYYY-MM.
2032 pub month: String,
2033 /// Trial grants made this month, against the month's pool.
2034 pub trial_granted_micros: i64,
2035 pub trial_pool_micros: i64,
2036 pub trial_grants: u32,
2037 /// What the open-source pool paid this month, against its cap.
2038 pub oss_used_micros: i64,
2039 pub oss_pool_micros: i64,
2040 /// Each public repository's monthly cap on the pool.
2041 pub oss_repo_micros: i64,
2042}
2043
2044#[derive(Clone, Debug, Serialize, Deserialize)]
2045#[serde(rename_all = "camelCase")]
2046pub struct KindFigures {
2047 pub kind: String,
2048 pub charged_micros: i64,
2049 pub cost_micros: i64,
2050}
2051
2052// --- Staff (sudo.g1t.sh) ------------------------------------------------------
2053//
2054// Called only by the sudo app, which only g1t staff can reach (behind
2055// Cloudflare Access). Each change names who made it, and is kept in the
2056// audit log.
2057
2058/// `admin_accounts`: every billing account, with where each stands this
2059/// month. Returns `Vec<AccountSummary>`.
2060#[derive(Debug, Default, Serialize, Deserialize)]
2061pub struct AdminAccountsArgs {
2062 #[serde(default)]
2063 pub query: Option<String>,
2064 /// Exactly these workspaces' accounts, such as one page of sudo's
2065 /// list; every account with activity when absent.
2066 #[serde(default)]
2067 pub workspaces: Option<Vec<String>>,
2068}
2069
2070#[derive(Clone, Debug, Serialize, Deserialize)]
2071#[serde(rename_all = "camelCase")]
2072pub struct AccountSummary {
2073 pub account: BillingAccount,
2074 pub limit: Limit,
2075 /// Charged this month, after terms.
2076 pub charged_micros: i64,
2077 /// What this month's usage cost g1t.
2078 pub cost_micros: i64,
2079 /// Paid, ever.
2080 pub paid_micros: i64,
2081 /// The same figures for each of the account's workspaces that has
2082 /// any, so staff can see what one member of an enterprise used.
2083 #[serde(default)]
2084 pub by_workspace: Vec<WorkspaceFigures>,
2085 /// The last six months, oldest first, for trends.
2086 #[serde(default)]
2087 pub months: Vec<MonthFigures>,
2088}
2089
2090/// One month of an account's billing.
2091#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2092#[serde(rename_all = "camelCase")]
2093pub struct MonthFigures {
2094 /// YYYY-MM.
2095 pub month: String,
2096 /// Usage charged, after what paid for it first.
2097 pub charged_micros: i64,
2098 /// What usage cost g1t: only what g1t paid for, never a workspace's own
2099 /// model provider.
2100 pub cost_micros: i64,
2101 pub paid_micros: i64,
2102 /// The plan's monthly price, paid.
2103 #[serde(default)]
2104 pub plans_micros: i64,
2105 /// What g1t gave, at price: internal (comped) use, trials, the
2106 /// open-source pool, goodwill credits and what g1t covered. Not margin.
2107 #[serde(default)]
2108 pub given_micros: i64,
2109}
2110
2111/// One workspace's share of an [`AccountSummary`].
2112#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2113#[serde(rename_all = "camelCase")]
2114pub struct WorkspaceFigures {
2115 pub workspace: String,
2116 pub charged_micros: i64,
2117 pub cost_micros: i64,
2118 pub paid_micros: i64,
2119}
2120
2121/// `admin_account`: one account in full. Returns `Outcome<AccountDetail>`.
2122#[derive(Debug, Serialize, Deserialize)]
2123pub struct AdminAccountArgs {
2124 /// An account id, or a workspace slug.
2125 pub id: String,
2126}
2127
2128#[derive(Clone, Debug, Serialize, Deserialize)]
2129#[serde(rename_all = "camelCase")]
2130pub struct AccountDetail {
2131 pub summary: AccountSummary,
2132 /// Each workspace's limit, for an enterprise.
2133 pub workspaces: Vec<Limit>,
2134 pub ledger: Vec<LedgerEntry>,
2135 pub audit: Vec<AdminAction>,
2136}
2137
2138/// `admin_set_terms`. Returns `Outcome<BillingAccount>`.
2139#[derive(Debug, Serialize, Deserialize)]
2140pub struct AdminSetTermsArgs {
2141 pub id: String,
2142 pub terms: Terms,
2143 pub by: String,
2144}
2145
2146/// `admin_create_enterprise`. Returns `Outcome<BillingAccount>`.
2147#[derive(Debug, Serialize, Deserialize)]
2148pub struct AdminCreateEnterpriseArgs {
2149 pub name: String,
2150 pub workspaces: Vec<String>,
2151 pub by: String,
2152}
2153
2154/// `admin_attach`: moves a workspace onto an enterprise account, or back
2155/// onto its own with `account: None`. Returns `Outcome<BillingAccount>`.
2156#[derive(Debug, Serialize, Deserialize)]
2157pub struct AdminAttachArgs {
2158 pub workspace: String,
2159 pub account: Option<String>,
2160 pub by: String,
2161}
2162
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging2163/// Why g1t gave a workspace credit.
2164#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
2165#[serde(rename_all = "snake_case")]
2166pub enum CreditKind {
2167 /// Marketing: a welcome, a referral, an event. Given away when spent.
2168 Promotional,
2169 /// An apology, or accidental usage forgiven. Given away when spent.
2170 #[default]
2171 Goodwill,
2172 /// Money back for something that went wrong. Not given away: it gives
2173 /// back money already paid, so it comes off what was paid on the day
2174 /// it refunds, and what it pays for later is paid for.
2175 Refund,
2176 /// Bought by the workspace (prepaid AI): money paid in up front, owed
2177 /// as usage until spent. What it pays for is paid for, never given.
2178 /// Staff never give it; its ledger line is a payment, not `crd…`.
2179 Purchased,
2180}
2181
2182impl CreditKind {
2183 pub fn as_str(self) -> &'static str {
2184 match self {
2185 CreditKind::Promotional => "promotional",
2186 CreditKind::Goodwill => "goodwill",
2187 CreditKind::Refund => "refund",
2188 CreditKind::Purchased => "purchased",
2189 }
2190 }
2191
2192 pub fn parse(text: &str) -> Option<CreditKind> {
2193 match text {
2194 "promotional" => Some(CreditKind::Promotional),
2195 "goodwill" => Some(CreditKind::Goodwill),
2196 "refund" => Some(CreditKind::Refund),
2197 "purchased" => Some(CreditKind::Purchased),
2198 _ => None,
2199 }
2200 }
2201
2202 /// As people read it: `Promotional`.
2203 pub fn label(self) -> &'static str {
2204 match self {
2205 CreditKind::Promotional => "Promotional",
2206 CreditKind::Goodwill => "Goodwill",
2207 CreditKind::Refund => "Refund",
2208 CreditKind::Purchased => "Purchased",
2209 }
2210 }
2211}
2212
2213/// `admin_credit`: credit g1t gives a workspace: promotional, goodwill or a
2214/// refund, with a note, and optionally an expiry. It is spent before
2215/// anything paid in advance, the soonest-expiring first. The workspace's
2216/// owners are emailed. Returns `Outcome<LedgerEntry>`.
Mission control counts people's direct pushes to the default branch2217#[derive(Debug, Serialize, Deserialize)]
2218pub struct AdminCreditArgs {
2219 pub workspace: String,
2220 pub amount_micros: i64,
2221 pub note: String,
2222 pub by: String,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging2223 #[serde(default)]
2224 pub kind: CreditKind,
2225 /// RFC 3339; unused credit stops counting then. Never for a refund.
2226 #[serde(default)]
2227 pub expires_at: Option<String>,
2228 /// A refund: what it refunds, in a line, and the day of it
2229 /// (`YYYY-MM-DD`; today if absent).
2230 #[serde(default)]
2231 pub refund_for: Option<String>,
2232 #[serde(default)]
2233 pub refund_day: Option<String>,
2234}
2235
2236/// One credit g1t gave, with what of it was used: spent on usage, the
2237/// soonest-expiring grant first, before anything paid in advance.
2238#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2239#[serde(rename_all = "camelCase")]
2240pub struct CreditGrant {
2241 /// `crd_…`, the grant's ledger reference.
2242 pub id: String,
2243 pub workspace: String,
2244 pub kind: CreditKind,
2245 pub amount_micros: i64,
2246 pub used_micros: i64,
2247 /// What can still be spent: nothing once it expired or was revoked.
2248 pub left_micros: i64,
2249 pub note: String,
2250 #[serde(default)]
2251 pub refund_for: Option<String>,
2252 #[serde(default)]
2253 pub refund_day: Option<String>,
2254 pub expires_at: Option<String>,
2255 pub created_by: String,
2256 pub created_at: String,
2257 /// `open`, `used`, `expired` or `revoked`.
2258 pub state: String,
2259 #[serde(default)]
2260 pub closed_at: Option<String>,
2261 #[serde(default)]
2262 pub closed_note: Option<String>,
2263 #[serde(default)]
2264 pub closed_by: Option<String>,
2265 /// What expiring or revoking took off the balance.
2266 #[serde(default)]
2267 pub closed_micros: i64,
2268 /// What it pays for: `all` usage, or `models` only (agent runs' model
2269 /// cost), which is spent first.
2270 #[serde(default)]
2271 pub scope: String,
2272 /// Where it came from: `staff`, `purchase` or `promo_code`.
2273 #[serde(default)]
2274 pub source: String,
2275}
2276
2277/// `credits` (`Outcome<Credits>`, `AccountArgs`): a workspace's credits from
2278/// g1t, newest first, for its members.
2279#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2280#[serde(rename_all = "camelCase")]
2281pub struct Credits {
2282 pub grants: Vec<CreditGrant>,
2283 /// What is left to spend, in all.
2284 pub left_micros: i64,
2285}
2286
2287/// `admin_credits`: every credit g1t gave, newest first, filtered. Returns
2288/// `AdminCredits`.
2289#[derive(Debug, Default, Serialize, Deserialize)]
2290pub struct AdminCreditsArgs {
2291 #[serde(default)]
2292 pub workspace: Option<String>,
2293 #[serde(default)]
2294 pub kind: Option<CreditKind>,
2295 /// `YYYY-MM`: given that month.
2296 #[serde(default)]
2297 pub month: Option<String>,
2298 /// Given by this member of staff.
2299 #[serde(default)]
2300 pub by: Option<String>,
2301}
2302
2303/// One month's credits of one kind: given, used on usage that month, and
2304/// taken back unused (expired or revoked).
2305#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2306#[serde(rename_all = "camelCase")]
2307pub struct CreditMonth {
2308 pub month: String,
2309 pub kind: CreditKind,
2310 pub given_micros: i64,
2311 pub grants: u32,
2312 pub used_micros: i64,
2313 pub expired_micros: i64,
2314 pub revoked_micros: i64,
2315}
2316
2317#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2318#[serde(rename_all = "camelCase")]
2319pub struct AdminCredits {
2320 /// At most 200.
2321 pub grants: Vec<CreditGrant>,
2322 /// The last 12 months, newest first, whatever the month filter.
2323 pub months: Vec<CreditMonth>,
2324 /// Who has given credit, for the filter.
2325 pub staff: Vec<String>,
2326}
2327
2328/// `admin_revoke_credit`: what is left of a grant, taken off the balance,
2329/// with why. Returns `Outcome<CreditGrant>`.
2330#[derive(Debug, Serialize, Deserialize)]
2331pub struct AdminRevokeCreditArgs {
2332 pub id: String,
2333 pub note: String,
2334 pub by: String,
Mission control counts people's direct pushes to the default branch2335}
2336
sudo: reset a test workspace's billing so it starts again as a new customer; refused on a live Stripe key, for comped workspaces and for an enterprise's2337/// `admin_reset_billing`: a test workspace's billing wiped, so it starts
2338/// again as a new customer. Only while billing runs on Stripe's test key;
2339/// never a comped workspace or one an enterprise pays for. `confirm` is the
2340/// workspace's slug typed out. Returns `Outcome<BillingReset>`.
2341#[derive(Debug, Serialize, Deserialize)]
2342pub struct AdminResetBillingArgs {
2343 pub workspace: String,
2344 pub confirm: String,
2345 pub note: String,
2346 pub by: String,
2347}
2348
2349/// What a reset removed.
2350#[derive(Clone, Debug, Serialize, Deserialize)]
2351#[serde(rename_all = "camelCase")]
2352pub struct BillingReset {
2353 pub workspace: String,
2354 pub rows: u32,
sudo: a billing reset runs the costs analysis again so every figure is fresh; every submit button shows it is working (CSS only); no margin percentage on less than a cent sold2355 /// Whether the costs analysis ran again after it, so the margin
2356 /// figures no longer hold the workspace's past usage.
2357 #[serde(default)]
2358 pub refreshed: bool,
sudo: reset a test workspace's billing so it starts again as a new customer; refused on a live Stripe key, for comped workspaces and for an enterprise's2359}
2360
Mission control counts people's direct pushes to the default branch2361/// One change made in sudo.
2362#[derive(Clone, Debug, Serialize, Deserialize)]
2363#[serde(rename_all = "camelCase")]
2364pub struct AdminAction {
2365 pub id: String,
2366 pub account: String,
2367 pub action: String,
2368 pub detail: String,
2369 pub by: String,
2370 pub created_at: String,
2371}
2372
2373/// What a feature's plan costs and includes.
2374#[derive(Clone, Debug, Serialize, Deserialize)]
2375#[serde(rename_all = "camelCase")]
2376pub struct Plan {
2377 pub feature: Feature,
2378 pub title: String,
Merge Stripe Tax, the card fee on card payments, and one free workspace per person2379 /// Charged every month while the plan is on, in cents, excluding tax.
Mission control counts people's direct pushes to the default branch2380 pub monthly_cents: u32,
Merge Stripe Tax, the card fee on card payments, and one free workspace per person2381 /// The card processing fee on top each month, in cents (0 when the
2382 /// fee is off). Excluding tax, like the price.
2383 #[serde(default)]
2384 pub card_fee_cents: u32,
Mission control counts people's direct pushes to the default branch2385 /// What the monthly price includes, one line each, for people to read.
2386 pub includes: Vec<String>,
2387 /// How usage past the allowance is charged, for people to read.
2388 pub overage: String,
2389}
2390
2391#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
2392#[serde(rename_all = "snake_case")]
2393pub enum SubscriptionStatus {
2394 /// Paid up; the feature works.
2395 Active,
2396 /// Paid up to the end of the period, and ends then.
2397 Canceling,
2398 /// The last payment failed; the feature is off until it is paid.
2399 PastDue,
2400 /// Ended.
2401 Canceled,
2402}
2403
2404impl SubscriptionStatus {
2405 /// Whether the feature works in this state.
2406 pub fn on(self) -> bool {
2407 matches!(self, SubscriptionStatus::Active | SubscriptionStatus::Canceling)
2408 }
2409}
2410
2411/// A workspace's plan for one feature.
2412#[derive(Clone, Debug, Serialize, Deserialize)]
2413#[serde(rename_all = "camelCase")]
2414pub struct Subscription {
2415 pub feature: Feature,
2416 pub status: SubscriptionStatus,
2417 /// RFC 3339: when the period paid for ends, and the plan renews or
2418 /// ends.
2419 pub period_end: Option<String>,
2420 /// Username of whoever turned it on.
2421 pub started_by: String,
2422 /// RFC 3339.
2423 pub started_at: String,
2424}
2425
2426/// A feature as a workspace sees it: what it costs, and its plan if it has
2427/// one.
2428#[derive(Clone, Debug, Serialize, Deserialize)]
2429#[serde(rename_all = "camelCase")]
2430pub struct FeatureState {
2431 pub plan: Plan,
2432 pub subscription: Option<Subscription>,
2433 /// Whether the feature works for the workspace now.
2434 pub on: bool,
2435 /// On without a plan: comped terms, or given by g1t. Nothing to pay
2436 /// and nothing to turn off.
2437 #[serde(default)]
2438 pub included: bool,
2439}
2440
2441/// `features`: every paid feature and the workspace's plan for each.
2442/// Members only. Returns `Outcome<Vec<FeatureState>>`.
2443#[derive(Debug, Serialize, Deserialize)]
2444pub struct FeaturesArgs {
2445 pub workspace: String,
2446 pub viewer: Viewer,
2447}
2448
2449/// `subscribe`: starts the card page for a feature's monthly plan. Owners
2450/// only. Returns `Outcome<Checkout>`; the page's id comes back to
2451/// `return_url` as `session`, for `confirm_subscription`.
2452#[derive(Debug, Serialize, Deserialize)]
2453#[serde(rename_all = "camelCase")]
2454pub struct SubscribeArgs {
2455 pub actor: User,
2456 pub workspace: String,
2457 pub feature: Feature,
2458 pub return_url: String,
2459}
2460
2461/// `confirm_subscription`: turns the feature on once the processor says
2462/// the plan was paid for. Safe to call any number of times. Returns
2463/// `Outcome<FeatureState>`.
2464#[derive(Debug, Serialize, Deserialize)]
2465pub struct ConfirmSubscriptionArgs {
2466 pub workspace: String,
2467 pub viewer: Viewer,
2468 pub session: String,
2469}
2470
2471/// `admin_log`: a staff change another service made to a workspace, kept
2472/// in sudo's audit log with billing's own (`admin_audit`). For identity's
2473/// restores and purges of deleted workspaces. Returns `bool`.
2474#[derive(Debug, Serialize, Deserialize)]
2475pub struct AdminLogArgs {
2476 pub workspace: String,
2477 pub action: String,
2478 pub detail: String,
2479 /// The staff member's email.
2480 pub by: String,
2481}
2482
2483/// `close_workspace`: settles a workspace that is about to be deleted.
2484/// Owners only. Refused while it has an invoice that failed, while it
2485/// holds prepaid credit, or while it owes money it cannot be charged for
2486/// now; otherwise what it owes is invoiced to its card at once (no
2487/// minimum), its plan is cancelled at Stripe straight away, and its
2488/// account is marked closed, so the month-end close, autopay and limit
2489/// warnings pass it by. Its ledger, invoices and statements stay. With
2490/// `dry_run`, only says whether it could, changing nothing. Returns
2491/// `Outcome<bool>`.
2492#[derive(Debug, Serialize, Deserialize)]
2493#[serde(rename_all = "camelCase")]
2494pub struct CloseWorkspaceArgs {
2495 pub actor: User,
2496 pub workspace: String,
2497 #[serde(default)]
2498 pub dry_run: bool,
2499}
2500
2501/// `cancel_subscription` (`resume` false) ends a plan at the end of the
2502/// period paid for; with `resume` true, takes that back. Owners only.
2503/// Returns `Outcome<FeatureState>`.
2504#[derive(Debug, Serialize, Deserialize)]
2505pub struct CancelSubscriptionArgs {
2506 pub actor: User,
2507 pub workspace: String,
2508 pub feature: Feature,
2509 #[serde(default)]
2510 pub resume: bool,
2511}
2512
2513/// `has_feature`: whether a feature works for a workspace now, asked by the
2514/// service that provides it before doing paid work. Returns
2515/// `Outcome<bool>`: a failure, with the reason to show, when it does not.
2516/// True everywhere when no card processor is configured.
2517#[derive(Debug, Serialize, Deserialize)]
2518pub struct HasFeatureArgs {
2519 pub workspace: String,
2520 pub feature: Feature,
2521}
2522
Merge Stripe Tax, the card fee on card payments, and one free workspace per person2523/// `free_workspaces`: which of `workspaces` are free, that is on no paid
2524/// plan. Paid is the g1t plan, an enterprise's terms, or a discount of
2525/// 100% (g1t's own workspaces). Identity asks before a workspace is made
2526/// (a person owns at most one free workspace) and before anyone is added
2527/// to one (a free workspace cannot invite). Returns `Vec<String>`, the
2528/// free ones, lower-cased; none where payments are not set up.
2529#[derive(Debug, Serialize, Deserialize)]
2530pub struct FreeWorkspacesArgs {
2531 pub workspaces: Vec<String>,
2532}
2533
Mission control counts people's direct pushes to the default branch2534/// `charge_feature`: usage of a feature past its plan's allowance, charged
2535/// from the workspace's credit at cost plus the margin, whatever
2536/// `FREE_WHILE_BUILDING` says. Called by the service that provides it.
2537/// Charged once per `reference`. Returns `Outcome<bool>`: false if that
2538/// reference was charged before.
2539#[derive(Debug, Serialize, Deserialize)]
2540#[serde(rename_all = "camelCase")]
2541pub struct ChargeFeatureArgs {
2542 pub workspace: String,
2543 pub feature: Feature,
2544 /// What it cost g1t, in millionths of a dollar, before the margin.
2545 pub cost_micros: i64,
2546 pub description: String,
2547 /// `namespace/name`, when the usage was one repository's.
2548 pub repo: Option<String>,
2549 /// Unique to this charge, e.g. `deployments/acme/2026-10`.
2550 pub reference: String,
2551 /// For a build: how long it ran. The plan's included build time this
2552 /// month pays for what it can, and only the rest of `cost_micros` is
2553 /// charged.
2554 #[serde(default)]
2555 pub build_seconds: Option<u32>,
2556}
2557
2558// ---------------------------------------------------------------------
2559// Costs and margin: what Cloudflare charges g1t against what g1t
2560// charges (billing's costs.rs, margin.rs and pricing.rs). Staff only.
2561// ---------------------------------------------------------------------
2562
2563/// `admin_costs`: the Costs & margin page. Returns `CostsReport`.
2564#[derive(Debug, Default, Serialize, Deserialize)]
2565pub struct AdminCostsArgs {
2566 /// How many days back, 7 to 90; 30 when absent.
2567 #[serde(default)]
2568 pub days: Option<u32>,
2569}
2570
2571/// One of g1t's products on one day.
2572#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2573#[serde(rename_all = "camelCase")]
2574pub struct CostDay {
2575 pub day: String,
2576 pub bucket: String,
2577 /// What Cloudflare charged g1t.
2578 pub cf_cost_micros: i64,
2579 /// What g1t's meters recorded it cost, at the price book's cost.
2580 pub own_cost_micros: i64,
2581 /// What customers were charged for it at price, before included
2582 /// usage, trials and pools paid for some.
2583 pub value_micros: i64,
2584 /// Of that, what workspaces paid.
2585 pub cash_micros: i64,
2586}
2587
2588/// One product over the range.
2589#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2590#[serde(rename_all = "camelCase")]
2591pub struct ProductMargin {
2592 pub bucket: String,
2593 pub title: String,
2594 /// The cost the margin is taken from: Cloudflare's bill, or g1t's own
2595 /// figure for what Cloudflare does not bill (models).
2596 pub cost_micros: i64,
2597 pub cf_cost_micros: i64,
2598 pub own_cost_micros: i64,
2599 pub value_micros: i64,
2600 pub margin_micros: i64,
2601 pub margin_percent: Option<f64>,
2602 /// `cloudflare` or `ledger`.
2603 pub cost_source: String,
2604 /// Running g1t itself, paid for by the plan.
2605 pub overhead: bool,
2606}
2607
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it2608/// All of g1t over the range: money in against every cost, and against
2609/// the cost of what was sold (every cost less what g1t gave away).
Mission control counts people's direct pushes to the default branch2610#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2611#[serde(rename_all = "camelCase")]
2612pub struct OverallMargin {
2613 /// What workspaces paid for usage, and for the plan.
2614 pub usage_micros: i64,
2615 pub plans_micros: i64,
2616 pub cost_micros: i64,
2617 pub margin_micros: i64,
2618 pub margin_percent: Option<f64>,
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it2619 /// Of `cost_micros`, what went on usage g1t gave away on purpose:
2620 /// comped workspaces, free periods, the trial and the open-source pool.
2621 #[serde(default)]
2622 pub given_micros: i64,
2623 /// Money in against `cost_micros - given_micros`.
2624 #[serde(default)]
2625 pub sold_margin_micros: i64,
2626 #[serde(default)]
2627 pub sold_margin_percent: Option<f64>,
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running2628 /// What was sold, apart: usage (`usage_micros` against what that usage
2629 /// cost, less what was given), running g1t (`plans_micros` against the
2630 /// platform's cost, less its given share) and what no mapping names.
2631 #[serde(default)]
2632 pub usage_cost_micros: i64,
2633 #[serde(default)]
2634 pub usage_margin_micros: i64,
2635 #[serde(default)]
2636 pub usage_margin_percent: Option<f64>,
2637 #[serde(default)]
2638 pub running_cost_micros: i64,
2639 #[serde(default)]
2640 pub unmapped_cost_micros: i64,
2641 /// `given_micros` by why: comped workspaces, free use (free periods,
2642 /// free allowances, overruns g1t covered), the trial, the open-source pool.
2643 #[serde(default)]
2644 pub given_comped_micros: i64,
2645 #[serde(default)]
2646 pub given_free_micros: i64,
2647 #[serde(default)]
2648 pub given_trial_micros: i64,
2649 #[serde(default)]
2650 pub given_pool_micros: i64,
Merge branch 'worktree-agent-a633ac0f7f66d419d'2651 /// What discounts on an account's terms took below cost plus the
2652 /// margin: given, so a discounted sale is not margin lost.
2653 #[serde(default)]
2654 pub given_discount_micros: i64,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging2655 /// Credits from g1t spent on usage, by kind: given, so usage paid for
2656 /// with them is never money in. Refunds are not here: they come off
2657 /// money in on the day they refund.
2658 #[serde(default)]
2659 pub given_credit_promotional_micros: i64,
2660 #[serde(default)]
2661 pub given_credit_goodwill_micros: i64,
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb972662 /// What testing resets wiped that g1t paid for (`reset_costs`): the
2663 /// model calls and Cloudflare usage still happened, so their cost is
2664 /// given, never a leak.
2665 #[serde(default)]
2666 pub given_reset_micros: i64,
Merge Cloudflare's usage over its billing cycle: every page read, included amounts once a cycle, a projection, test-mode charges never money in (billing 0052)2667 /// What workspaces were charged while payments were not live (Stripe's
2668 /// test mode): no real money came in, so it is given, never money in.
2669 #[serde(default)]
2670 pub given_unpaid_micros: i64,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging2671 /// Credits over the range: given (every kind), spent on usage, and
2672 /// refunds' money given back.
2673 #[serde(default)]
2674 pub credits_given_micros: i64,
2675 #[serde(default)]
2676 pub credits_used_micros: i64,
2677 #[serde(default)]
2678 pub credits_refunded_micros: i64,
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running2679 /// `cost_micros` by who g1t pays: Cloudflare's bill (billed amounts,
2680 /// after the included allowances), and model providers (the ledger's
2681 /// cost of the tokens, which Cloudflare's bill does not show).
Costs: the plan's included usage counts as paid for the usage it covered, out of what plans leave for running g1t; the run button shows it is running with CSS alone (sudo ships no JavaScript)2682 /// What the plan's included usage paid for, at price (the ledger's
2683 /// `credit_micros`, comped workspaces left out): money in for usage,
2684 /// paid out of `plans_micros`.
2685 #[serde(default)]
2686 pub included_micros: i64,
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running2687 #[serde(default)]
2688 pub cloudflare_cost_micros: i64,
2689 #[serde(default)]
2690 pub models_cost_micros: i64,
Merge Stripe Tax, the card fee on card payments, and one free workspace per person2691 /// Tax collected with payments over the range, net of refunds: owed to
2692 /// the tax authorities, never in cash or revenue.
2693 #[serde(default)]
2694 pub tax_collected_micros: i64,
2695 /// Card processing fees passed on with card payments, net of refunds:
2696 /// they pay Stripe's fee, so they are not revenue either.
2697 #[serde(default)]
2698 pub card_fees_micros: i64,
Merge Cloudflare's usage over its billing cycle: every page read, included amounts once a cycle, a projection, test-mode charges never money in (billing 0052)2699 /// Cloudflare's subscriptions over the range: each day's share of the
2700 /// billing cycle it is in (a month's price over the cycle's days), the
2701 /// same accrual g1t's own spend uses for the calendar month.
2702 #[serde(default)]
2703 pub subscriptions_micros: i64,
2704 /// What AI Gateway priced g1t's own provider traffic at over the range
2705 /// (Cloudflare-billed requests left out): what the providers bill, to
2706 /// set beside `models_cost_micros`, the ledger's figure.
2707 #[serde(default)]
2708 pub gateway_cost_micros: i64,
Mission control counts people's direct pushes to the default branch2709}
2710
2711/// A count, cost or leak that does not add up.
2712#[derive(Clone, Debug, Serialize, Deserialize)]
2713#[serde(rename_all = "camelCase")]
2714pub struct CostDrift {
2715 pub bucket: String,
2716 pub title: String,
2717 /// `count` (units g1t counted against Cloudflare's), `cost` (the bill
Merge branch 'worktree-agent-a633ac0f7f66d419d'2718 /// against the price book's cost of the same usage; for models, what AI
2719 /// Gateway priced g1t's provider traffic at against the ledger's model
2720 /// cost), `unpriced` (model usage AI Gateway put no price on, so its
2721 /// cost is not the providers'), or `leak`.
Mission control counts people's direct pushes to the default branch2722 pub kind: String,
2723 pub ours: f64,
2724 pub cloudflare: f64,
2725 pub delta_percent: Option<f64>,
2726 pub detail: String,
2727 pub found_at: String,
2728}
2729
2730/// A margin alert, open while its condition lasts.
2731#[derive(Clone, Debug, Serialize, Deserialize)]
2732#[serde(rename_all = "camelCase")]
2733pub struct MarginAlert {
2734 pub id: String,
2735 /// `margin`, `overall`, `leak`, `drift` or `workspace`.
2736 pub kind: String,
2737 /// The product, or the workspace.
2738 pub subject: String,
2739 pub detail: String,
2740 pub since: String,
2741 pub opened_at: String,
2742 pub emailed_at: Option<String>,
2743}
2744
2745/// A change to a price the reconciler measured.
2746#[derive(Clone, Debug, Serialize, Deserialize)]
2747#[serde(rename_all = "camelCase")]
2748pub struct PriceProposal {
2749 pub id: String,
2750 pub meter: String,
2751 pub title: String,
2752 pub unit: String,
2753 pub current_cost_micros: f64,
2754 pub proposed_cost_micros: f64,
2755 pub change_percent: f64,
2756 pub markup_percent: u32,
2757 pub reason: String,
2758 /// `keeper` or `reconciler`.
2759 pub source: String,
2760 /// Far off the current cost: look before approving.
2761 pub suspect: bool,
2762 /// `open`, `applied`, `approved`, `rejected` or `superseded`.
2763 pub status: String,
2764 pub created_at: String,
2765 pub decided_at: Option<String>,
2766 pub decided_by: Option<String>,
2767 pub note: Option<String>,
2768 /// When it takes or took effect, once approved or applied.
2769 pub effective_at: Option<String>,
2770}
2771
2772/// One version of one meter's price. Never changed once written.
2773#[derive(Clone, Debug, Serialize, Deserialize)]
2774#[serde(rename_all = "camelCase")]
2775pub struct PriceVersion {
2776 pub id: String,
2777 pub meter: String,
2778 pub version: u32,
2779 pub cost_micros: f64,
2780 pub markup_percent: u32,
2781 pub price_micros: f64,
2782 pub effective_at: String,
2783 pub reason: String,
2784 pub created_by: String,
2785 /// When the price book took it on; absent while it waits for its date.
2786 pub applied_at: Option<String>,
Merge costs and margin review: gateway query, own spend, discount meters, superseded rises2787 /// What `cost_micros` is: `cost`, what g1t pays for a unit (a
2788 /// provider's dollar passed on at cost is one); `rate`, a price g1t
2789 /// sets with no cost behind it (the agent rate, security activation),
2790 /// so its cost column is its price; `weight`, a multiplier in
2791 /// millionths, not money (the agent rate's token weights).
2792 #[serde(default)]
2793 pub basis: String,
Mission control counts people's direct pushes to the default branch2794}
2795
2796/// What a workspace cost g1t over the range, Cloudflare's costs shared
2797/// out by g1t's own meters, against what it paid.
2798#[derive(Clone, Debug, Serialize, Deserialize)]
2799#[serde(rename_all = "camelCase")]
2800pub struct WorkspaceCost {
2801 pub workspace: String,
2802 pub cost_micros: i64,
2803 pub revenue_micros: i64,
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it2804 /// Of `cost_micros`, what g1t gave away.
2805 #[serde(default)]
2806 pub given_micros: i64,
Mission control counts people's direct pushes to the default branch2807 /// One of g1t's own (comped) workspaces.
2808 pub internal: bool,
2809}
2810
2811/// One Cloudflare meter over the range, and the product it is a cost of.
2812#[derive(Clone, Debug, Serialize, Deserialize)]
2813#[serde(rename_all = "camelCase")]
2814pub struct CostLineSummary {
2815 pub product: String,
2816 pub meter: String,
2817 pub raw_name: String,
2818 pub unit: String,
2819 pub source: String,
2820 pub quantity: f64,
2821 pub cost_micros: i64,
2822 /// Absent when no mapping claims it.
2823 pub bucket: Option<String>,
2824}
2825
2826/// A row of the mapping from Cloudflare's meters to g1t's products.
2827#[derive(Clone, Debug, Serialize, Deserialize)]
2828#[serde(rename_all = "camelCase")]
2829pub struct CostMapping {
2830 pub product: String,
2831 pub meter: String,
2832 pub bucket: String,
2833 pub price_meter: Option<String>,
2834 pub own_meter: Option<String>,
2835 pub scale_to_own: bool,
2836 pub drift_percent: f64,
2837 pub note: String,
2838 pub updated_at: String,
2839 pub updated_by: String,
2840}
2841
2842/// The guardrails on prices and the alerts.
2843#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
2844#[serde(rename_all = "camelCase")]
2845pub struct CostSettings {
2846 /// Apply small moves without staff.
2847 pub auto_apply: bool,
2848 /// The largest move applied without staff, either way, in percent.
2849 pub auto_apply_percent: f64,
2850 /// Days between telling customers of a rise and charging it.
2851 pub notice_days: u32,
2852 /// Below this margin, in percent, for `alert_days` days in a row, alert.
2853 pub margin_floor_percent: f64,
2854 pub alert_days: u32,
2855 /// Days with less cost than this say nothing about a margin.
2856 pub min_daily_cost_micros: i64,
2857 /// A workspace costing more than its revenue times this, over 30 days,
2858 /// and at least `anomaly_floor_micros`, is flagged.
2859 pub anomaly_factor: f64,
2860 pub anomaly_floor_micros: i64,
Merge Stripe Tax, the card fee on card payments, and one free workspace per person2861 /// Pass Stripe's card fee on as its own line on every card payment (the
2862 /// plan, Security and quality, prepaying, AI credit, auto-reload and
2863 /// invoices charged to a card), never on a bank transfer or an invoice
2864 /// sent to be paid (`card_fee_percent` and `card_fee_fixed` in the
2865 /// price book). On by default.
Usage, Billing settings and prepaid AI credit; fixes from the UX audit2866 #[serde(default = "yes")]
2867 pub card_fee: bool,
Mission control counts people's direct pushes to the default branch2868}
2869
2870impl Default for CostSettings {
2871 fn default() -> Self {
2872 CostSettings {
2873 auto_apply: true,
2874 auto_apply_percent: 25.0,
2875 notice_days: 14,
2876 margin_floor_percent: 10.0,
2877 alert_days: 3,
2878 min_daily_cost_micros: 100_000,
2879 anomaly_factor: 1.0,
2880 anomaly_floor_micros: 1_000_000,
Usage, Billing settings and prepaid AI credit; fixes from the UX audit2881 card_fee: true,
Mission control counts people's direct pushes to the default branch2882 }
2883 }
2884}
2885
2886/// The Costs & margin page.
2887#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2888#[serde(rename_all = "camelCase")]
2889pub struct CostsReport {
2890 /// A token to read Cloudflare's bill is set.
2891 pub configured: bool,
2892 /// When Cloudflare's bill was last read.
2893 pub fetched_at: Option<String>,
2894 /// The days shown, YYYY-MM-DD.
2895 pub since: String,
2896 pub until: String,
2897 pub days: Vec<CostDay>,
2898 pub products: Vec<ProductMargin>,
2899 pub overall: OverallMargin,
2900 pub drift: Vec<CostDrift>,
2901 pub alerts: Vec<MarginAlert>,
2902 pub proposals: Vec<PriceProposal>,
2903 pub versions: Vec<PriceVersion>,
2904 pub top_workspaces: Vec<WorkspaceCost>,
2905 pub lines: Vec<CostLineSummary>,
2906 pub mappings: Vec<CostMapping>,
2907 pub settings: CostSettings,
2908 /// g1t's own spend against its two caps.
2909 #[serde(default)]
2910 pub caps: SpendCaps,
Merge Cloudflare's usage over its billing cycle: every page read, included amounts once a cycle, a projection, test-mode charges never money in (billing 0052)2911 /// Cloudflare's current billing cycle: its usage cost so far, by meter,
2912 /// and where it is heading. Absent until the bill has been read.
2913 #[serde(default)]
2914 pub cycle: Option<CloudflareCycle>,
2915 /// The last read of Cloudflare's billable usage: what came back.
2916 #[serde(default)]
2917 pub bill_read: Option<BillRead>,
2918 /// Of the range's cost, what no workspace's usage could carry (a day
2919 /// with no usage at all): running g1t, attributed to no one. The
2920 /// workspaces' costs and this add up to the cost.
2921 #[serde(default)]
2922 pub unattributed_micros: i64,
Mission control counts people's direct pushes to the default branch2923}
2924
Merge Cloudflare's usage over its billing cycle: every page read, included amounts once a cycle, a projection, test-mode charges never money in (billing 0052)2925/// Cloudflare's billing cycle (monthly, from the day the account's
2926/// subscription renews), as Cloudflare's Billable usage page shows it.
2927#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2928#[serde(rename_all = "camelCase")]
2929pub struct CloudflareCycle {
2930 /// The cycle's first and last days, YYYY-MM-DD, UTC.
2931 pub start: String,
2932 pub end: String,
2933 pub days: u32,
2934 /// Days from its start to today, today included.
2935 pub days_elapsed: u32,
2936 /// Usage cost so far, after the included allowances.
2937 pub usage_micros: i64,
2938 /// `usage_micros` over the days elapsed, times the cycle's days.
2939 pub projected_micros: i64,
2940 pub average_daily_micros: i64,
2941 /// Cloudflare's subscriptions for the cycle (not on the usage bill).
2942 pub subscriptions_micros: i64,
2943 pub meters: Vec<CycleMeter>,
2944}
2945
2946/// One of Cloudflare's meters over the cycle so far.
2947#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2948#[serde(rename_all = "camelCase")]
2949pub struct CycleMeter {
2950 pub product: String,
2951 pub meter: String,
2952 pub raw_name: String,
2953 pub unit: String,
2954 /// What was used.
2955 pub quantity: f64,
2956 /// What the cycle includes, in the same unit; None without a list price.
2957 pub included: Option<f64>,
2958 /// Past the included amount, as Cloudflare bills it.
2959 pub billable_quantity: f64,
2960 pub cost_micros: i64,
2961 /// `cloudflare` (the cost Cloudflare put on its lines), `list` (the
2962 /// list price past the included amount, while Cloudflare's lines carry
2963 /// no cost), or `none` (no list price known: costed at $0).
2964 pub basis: String,
2965}
2966
2967/// What the last read of Cloudflare's billable usage got back.
2968#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2969#[serde(rename_all = "camelCase")]
2970pub struct BillRead {
2971 pub read_at: String,
2972 pub since: String,
2973 pub until: String,
2974 pub rows: u32,
2975 pub pages: u32,
2976 /// Rows with a consumed quantity (`ConsumedQuantity`), and rows with
2977 /// only a pricing quantity.
2978 pub consumed_rows: u32,
2979 pub pricing_only_rows: u32,
2980 /// Rows Cloudflare put a cost on.
2981 pub costed_rows: u32,
2982}
2983
Mission control counts people's direct pushes to the default branch2984/// What g1t itself pays for, against its caps (billing's `budget`): the
2985/// daily breaker on all of it, and each comped account's monthly budget.
Costs: Cloudflare's subscriptions read from Cloudflare each day, the estimate only until then; sudo's costs split into Costs & margin and Bill & pricing2986/// One of Cloudflare's subscriptions, at what it comes to a month.
2987#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2988#[serde(rename_all = "camelCase")]
2989pub struct FixedCost {
2990 pub name: String,
2991 pub monthly_micros: i64,
2992}
2993
Mission control counts people's direct pushes to the default branch2994/// At cost, never at price. What sudo's Costs page and its red bar show.
2995#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2996#[serde(rename_all = "camelCase")]
2997pub struct SpendCaps {
2998 /// Today (UTC), YYYY-MM-DD, and this month, YYYY-MM.
2999 pub day: String,
3000 pub month: String,
3001 /// What g1t paid for itself today across every workspace: comped work,
3002 /// the trial and open-source pools, free workspaces' overruns, and
3003 /// anything charged without real money behind it.
3004 pub today_micros: i64,
3005 /// `PLATFORM_DAILY_SPEND_CAP_MICROS`. Zero: no breaker.
3006 pub daily_cap_micros: i64,
Merge main into rm-agents: mirroring removal, open signups, free-tier limits, the g1t CLI and runner fixes, with the agent removal kept. The CLI's table of operations is regenerated from the API without the agent, customize and AI credit operations; no CLI command used them.3007 /// The breaker is open: new compute that g1t would pay
Mission control counts people's direct pushes to the default branch3008 /// for wait until tomorrow (UTC) or until staff lift it.
3009 pub tripped: bool,
3010 pub tripped_at: Option<String>,
3011 /// Staff lifted it for the rest of the day.
3012 pub lifted_by: Option<String>,
3013 pub lifted_at: Option<String>,
3014 pub lift_note: Option<String>,
3015 /// This month so far, by what paid: `comped`, `trial`, `oss`, `given`,
3016 /// `unpaid`.
3017 pub month_buckets: Vec<SpendBucket>,
3018 /// Each comped account's monthly budget.
3019 pub comped: Vec<CompedBudget>,
3020 /// Free workspaces' share of this month's reconciled costs (git,
3021 /// storage, platform), through yesterday.
3022 pub free_tier_micros: i64,
Costs: Cloudflare's subscriptions read from Cloudflare each day, the estimate only until then; sudo's costs split into Costs & margin and Bill & pricing3023 /// Cloudflare's subscriptions a month: as read from Cloudflare each
3024 /// day, else `CLOUDFLARE_FIXED_MONTHLY_MICROS`, an estimate.
Mission control counts people's direct pushes to the default branch3025 pub fixed_monthly_micros: i64,
Costs: Cloudflare's subscriptions read from Cloudflare each day, the estimate only until then; sudo's costs split into Costs & margin and Bill & pricing3026 /// `cloudflare` or `estimate`.
3027 #[serde(default)]
3028 pub fixed_source: String,
3029 #[serde(default)]
3030 pub fixed_read_at: Option<String>,
3031 /// Each subscription, when read from Cloudflare.
3032 #[serde(default)]
3033 pub fixed_items: Vec<FixedCost>,
Merge Cloudflare's usage over its billing cycle: every page read, included amounts once a cycle, a projection, test-mode charges never money in (billing 0052)3034 /// Of `fixed_monthly_micros`, this calendar month's days so far: each
3035 /// day's share of the billing cycle it is in, today included.
3036 #[serde(default)]
3037 pub fixed_month_micros: i64,
Mission control counts people's direct pushes to the default branch3038 /// Money in this month, through the last reconciled day.
3039 pub revenue_micros: i64,
Merge costs and margin review: gateway query, own spend, discount meters, superseded rises3040 /// Of this month's buckets, what was spent on workspaces whose billing
3041 /// a testing reset later wiped: still g1t's spend, but no longer on
3042 /// their ledger, so the reconciled figures have it only where the
3043 /// reset kept it (as given away, testing resets).
3044 #[serde(default)]
3045 pub reset_micros: i64,
3046 /// Those workspaces.
3047 #[serde(default)]
3048 pub reset_workspaces: Vec<String>,
Mission control counts people's direct pushes to the default branch3049}
3050
3051#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3052#[serde(rename_all = "camelCase")]
3053pub struct SpendBucket {
3054 pub bucket: String,
3055 pub title: String,
3056 pub micros: i64,
3057}
3058
3059/// A comped account's monthly budget: what its work cost g1t this month.
3060#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3061#[serde(rename_all = "camelCase")]
3062pub struct CompedBudget {
3063 pub account: String,
3064 pub name: String,
3065 pub used_micros: i64,
3066 /// Zero: no budget.
3067 pub ceiling_micros: i64,
3068 /// The ceiling is `COMPED_MONTHLY_CEILING_MICROS`, not the account's own.
3069 pub default_ceiling: bool,
3070 /// 50, 75, 90, 100, or 0.
3071 pub level: u32,
3072}
3073
3074/// `admin_spend_caps`: g1t's own spend against its caps. Returns `SpendCaps`.
3075#[derive(Debug, Default, Serialize, Deserialize)]
3076pub struct AdminSpendCapsArgs {}
3077
Merge main into rm-agents: mirroring removal, open signups, free-tier limits, the g1t CLI and runner fixes, with the agent removal kept. The CLI's table of operations is regenerated from the API without the agent, customize and AI credit operations; no CLI command used them.3078/// `admin_lift_breaker`: lets runs g1t pays for start again for the rest
Mission control counts people's direct pushes to the default branch3079/// of today (UTC), with why. Recorded in the audit log. Returns
3080/// `Outcome<SpendCaps>`.
3081#[derive(Debug, Serialize, Deserialize)]
3082pub struct AdminLiftBreakerArgs {
3083 pub note: String,
3084 pub by: String,
3085}
3086
The docs folder is gone, and what it held lives where people read it: how a self-hosted g1t runs and how to deploy g1t to Cloudflare are pages on docs.g1t.sh under Run g1t yourself, and speed, rate limits and operating g1t.sh are sections of CONTRIBUTING.md; code that cited a file in docs/ now points to the page or section that covers it, or says what it means itself, and applied migrations and the runner images are left as they were.3087// ---- Platform pauses and the usage watcher ----
3088// docs.g1t.sh/guides/deploy-to-cloudflare/#spend-guardrails
Merge platform pause and the hourly usage watcher: staff can pause compute, schedules, indexing or renders for everyone, the watcher emails on a breach and is never blind quietly, and the models proxy holds each run to its cap (billing 0051, integrations 0006)3089
3090/// A g1t-wide pause, set by staff in sudo or by billing's hourly usage
3091/// watcher on a severe breach. Each level is independent.
3092#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
3093#[serde(rename_all = "snake_case")]
3094pub enum PauseLevel {
3095 /// Agents, sandboxes, Actions hosted jobs, deploy builds: every
3096 /// reservation through billing's `reserve` but embeddings.
3097 Compute,
3098 /// Actions' cron-triggered runs, and the runner's sweep that starts
3099 /// queued agents.
3100 Schedules,
3101 /// Context embeddings and backfills, and search's backfills.
3102 Indexing,
3103 /// Social card rendering, which falls back to a static image.
3104 Renders,
3105}
3106
3107impl PauseLevel {
3108 pub const ALL: [PauseLevel; 4] = [PauseLevel::Compute, PauseLevel::Schedules, PauseLevel::Indexing, PauseLevel::Renders];
3109
3110 pub fn as_str(self) -> &'static str {
3111 match self {
3112 PauseLevel::Compute => "compute",
3113 PauseLevel::Schedules => "schedules",
3114 PauseLevel::Indexing => "indexing",
3115 PauseLevel::Renders => "renders",
3116 }
3117 }
3118
3119 pub fn parse(text: &str) -> Option<PauseLevel> {
3120 PauseLevel::ALL.into_iter().find(|level| level.as_str() == text.trim())
3121 }
3122}
3123
3124/// `platform_pause`: which levels are paused now. Takes nothing. Callers
3125/// keep the answer about 30 seconds; one that cannot read it runs (fails
3126/// open).
3127#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
3128pub struct PlatformPause {
3129 #[serde(default)]
3130 pub compute: bool,
3131 #[serde(default)]
3132 pub schedules: bool,
3133 #[serde(default)]
3134 pub indexing: bool,
3135 #[serde(default)]
3136 pub renders: bool,
3137}
3138
3139impl PlatformPause {
3140 pub fn is(&self, level: PauseLevel) -> bool {
3141 match level {
3142 PauseLevel::Compute => self.compute,
3143 PauseLevel::Schedules => self.schedules,
3144 PauseLevel::Indexing => self.indexing,
3145 PauseLevel::Renders => self.renders,
3146 }
3147 }
3148
3149 pub fn set(&mut self, level: PauseLevel, paused: bool) {
3150 match level {
3151 PauseLevel::Compute => self.compute = paused,
3152 PauseLevel::Schedules => self.schedules = paused,
3153 PauseLevel::Indexing => self.indexing = paused,
3154 PauseLevel::Renders => self.renders = paused,
3155 }
3156 }
3157
3158 pub fn any(&self) -> bool {
3159 PauseLevel::ALL.into_iter().any(|level| self.is(level))
3160 }
3161}
3162
3163/// One level as sudo shows it: who paused it, when and why.
3164#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3165pub struct PauseState {
3166 pub level: String,
3167 pub paused: bool,
3168 pub note: Option<String>,
3169 pub set_by: Option<String>,
3170 pub set_at: Option<String>,
3171 /// Set by the usage watcher, not a person.
3172 pub auto: bool,
3173}
3174
3175/// One metric's usage over an hour or the month so far.
3176#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3177pub struct PlatformMetric {
3178 pub metric: String,
3179 pub title: String,
3180 pub value: f64,
3181 /// Its hourly threshold (`PLATFORM_HOURLY_*`); zero: none.
3182 pub threshold: f64,
3183 /// The script, queue, database or namespace that counted most.
3184 pub top_name: Option<String>,
3185 pub top_value: Option<f64>,
3186}
3187
3188/// A breach the watcher found.
3189#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3190pub struct PlatformBreach {
3191 pub id: String,
3192 pub metric: String,
3193 pub hour: String,
3194 /// `threshold` or `spike`.
3195 pub rule: String,
3196 pub value: f64,
3197 pub threshold: f64,
3198 pub severe: bool,
3199 pub top_name: Option<String>,
3200 pub detail: String,
3201 /// Levels it paused.
3202 pub paused: Vec<String>,
3203 pub opened_at: String,
3204 pub emailed_at: Option<String>,
3205}
3206
3207/// `admin_platform_guard`: the pauses, the last hour read, the month so
3208/// far and the last day's breaches, for sudo's Costs page and its banner.
3209#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3210pub struct PlatformGuard {
3211 pub levels: Vec<PauseState>,
3212 /// The last hour the watcher read (`YYYY-MM-DDTHH:00:00Z`), if any.
3213 pub hour: Option<String>,
3214 pub last_hour: Vec<PlatformMetric>,
3215 pub month: String,
3216 pub month_to_date: Vec<PlatformMetric>,
3217 /// The last 24 hours' breaches, newest first.
3218 pub breaches: Vec<PlatformBreach>,
3219 /// Whether the watcher can read Cloudflare's analytics at all.
3220 pub can_read: bool,
3221 /// `AUTO_PAUSE`: the levels a severe breach may pause.
3222 pub auto_pause: Vec<String>,
3223 /// What the latest run could not see: each query that failed.
3224 #[serde(default)]
3225 pub blind: Vec<BlindQuery>,
3226 /// The latest run found every dataset empty (the wrong account, or a
3227 /// token that cannot see its analytics).
3228 #[serde(default)]
3229 pub empty: bool,
3230 /// The hour the latest run read.
3231 #[serde(default)]
3232 pub last_run: Option<String>,
3233}
3234
3235/// A query the watcher's latest run could not read.
3236#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3237pub struct BlindQuery {
3238 pub key: String,
3239 pub dataset: String,
3240 pub error: String,
3241}
3242
3243/// `admin_platform_guard`. Returns `PlatformGuard`.
3244#[derive(Debug, Default, Serialize, Deserialize)]
3245pub struct AdminPlatformGuardArgs {}
3246
3247/// `admin_set_pause`: pauses or resumes one level, with why. Recorded in
3248/// the audit log. Returns `Outcome<PlatformGuard>`.
3249#[derive(Debug, Serialize, Deserialize)]
3250pub struct AdminSetPauseArgs {
3251 pub level: String,
3252 pub paused: bool,
3253 pub note: String,
3254 pub by: String,
3255}
3256
Mission control counts people's direct pushes to the default branch3257/// `admin_cost_alerts`: the open margin alerts, for sudo's banner.
3258/// Returns `Vec<MarginAlert>`.
3259#[derive(Debug, Default, Serialize, Deserialize)]
3260pub struct AdminCostAlertsArgs {}
3261
3262/// `admin_decide_proposal`: approve or reject a price proposal. An
3263/// approved rise takes effect after the notice period. Returns
3264/// `Outcome<PriceProposal>`.
3265#[derive(Debug, Serialize, Deserialize)]
3266pub struct AdminDecideProposalArgs {
3267 pub id: String,
3268 /// `approve` or `reject`.
3269 pub decision: String,
3270 #[serde(default)]
3271 pub note: String,
3272 pub by: String,
3273}
3274
3275/// `admin_set_cost_settings`. Returns `Outcome<CostSettings>`.
3276#[derive(Debug, Serialize, Deserialize)]
3277pub struct AdminSetCostSettingsArgs {
3278 pub settings: CostSettings,
3279 pub by: String,
3280}
3281
3282/// `admin_set_cost_mapping`: adds, changes or (with `remove`) removes a
3283/// mapping row. Returns `Outcome<CostMapping>`.
3284#[derive(Debug, Serialize, Deserialize)]
3285pub struct AdminSetCostMappingArgs {
3286 pub product: String,
3287 pub meter: String,
3288 #[serde(default)]
3289 pub bucket: String,
3290 #[serde(default)]
3291 pub price_meter: Option<String>,
3292 #[serde(default)]
3293 pub own_meter: Option<String>,
3294 #[serde(default)]
3295 pub scale_to_own: bool,
3296 #[serde(default)]
3297 pub drift_percent: Option<f64>,
3298 #[serde(default)]
3299 pub note: String,
3300 #[serde(default)]
3301 pub remove: bool,
3302 pub by: String,
3303}
3304
3305/// `admin_run_costs`: reads Cloudflare's bill and reconciles now, as the
3306/// daily run does. Returns `Outcome<CostsRun>`.
3307#[derive(Debug, Default, Serialize, Deserialize)]
3308pub struct AdminRunCostsArgs {
3309 #[serde(default)]
3310 pub by: String,
3311}
3312
3313#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3314#[serde(rename_all = "camelCase")]
3315pub struct CostsRun {
3316 pub lines: u32,
3317 pub days: u32,
3318 pub proposals: u32,
3319 pub alerts: u32,
3320 /// What could not be read, in words.
3321 pub problems: Vec<String>,
3322}
3323
Usage, Billing settings and prepaid AI credit; fixes from the UX audit3324// --- The Usage page ----------------------------------------------------------
3325
3326/// The product families the Usage page groups meters into, in order, with
3327/// their names.
The contracts no longer describe g1t's own agents, and workspaces can keep their AI providers. Every consumer had already stopped using them, so the TypeScript and Rust contracts drop the workspace-agent, ability, look, skill-library, context, runner-agent and mention modules, the chat and docs RPCs agents posted and read through, the folio agent methods, the agent_waiting notification, agent.asked and memory.changed events, AI credit, token and gateway billing types, model routes and sessions, team agents, agent tokens, plan, review, message and confidence types, command rules, cost caps and confidence rules. The agents:run and models:* scopes are no longer offered by any preset, OAuth default or permission form, but a stored token or grant that names them still reads; and the removed operations are gone from the scope table, so the API's check that every operation has exactly one scope is strict again. What stored data needs in order to parse (old run and credential kinds, an agent team lead, retired rules and webhook events, old guardrail and integration settings) still parses, and a run's token is still PrincipalKind::Agent, which now means a run's token and the @g1t rows written before. The customize, marketplace, skills and claude-plugin contracts stay only until the mobile app drops its Customize screens.3328pub const PRODUCTS: [(&str, &str); 6] = [
Usage, Billing settings and prepaid AI credit; fixes from the UX audit3329 ("sandboxes", "Sandboxes"),
3330 ("deployments", "Deployments"),
3331 ("git_storage", "Git & storage"),
3332 ("packages", "Packages"),
3333 ("security", "Security & quality"),
3334 ("search", "Search"),
3335];
3336
3337/// `usage_report`: a workspace's usage over a range of days, at price, by
3338/// product, meter, project and day. The figures are the ledger's: the same
3339/// lines the statement and invoices read, so every page agrees. Members
3340/// only. Returns `Outcome<UsageReport>`.
3341#[derive(Debug, Serialize, Deserialize)]
3342#[serde(rename_all = "camelCase")]
3343pub struct UsageReportArgs {
3344 pub workspace: String,
3345 pub viewer: Viewer,
3346 /// The first day, `YYYY-MM-DD` (UTC).
3347 pub from: String,
3348 /// The last day, `YYYY-MM-DD`, included.
3349 pub until: String,
3350 /// Only these product families (`agent`, `sandboxes`…); all when empty.
3351 #[serde(default)]
3352 pub products: Vec<String>,
3353 /// Only these projects (repositories, `owner/name`); all when empty.
3354 #[serde(default)]
3355 pub projects: Vec<String>,
3356}
3357
3358/// What usage came to over a range, and what paid for it. `price_micros`
3359/// less `discount_micros`, `included_micros` and `credits_micros` is
3360/// `charged_micros`.
3361#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
3362#[serde(rename_all = "camelCase")]
3363pub struct UsageTotals {
3364 /// Usage at price, metered usage not yet charged (`pending_micros`)
3365 /// included.
3366 pub price_micros: i64,
3367 /// What the account's discount took off.
3368 pub discount_micros: i64,
3369 /// What the plan's included usage, the trial and g1t's pools paid.
3370 pub included_micros: i64,
3371 /// What credit paid: AI credit, credit from g1t.
3372 pub credits_micros: i64,
3373 /// What is left for the workspace to pay.
3374 pub charged_micros: i64,
3375 /// Metered this month and charged when it closes (storage, git
3376 /// operations, scans, embeddings, domains), at price.
3377 pub pending_micros: i64,
Money is written one way. A single formatter turns millionths of a dollar into dollars, rounding half up on whole micros rather than on a float, so the same sum reads the same on every page: under a cent reads <$0.01 on a total and exactly nothing is $0.00, while the statement's lines, a session's receipt, the price book and an agent's effort costs carry up to four places where the fraction of a cent is the point; the six formatters that each rounded their own way are gone. This month is the calendar month in UTC from its first day to today everywhere, and billing counts the month's not-yet-closed usage in any range that reaches into the current month, so the top bar's pill, Spend, Home and Usage ask for the same days and get the same figure; Home now reads the usage report the others read instead of adding up statements. Usage's pending sentence says what of that usage the close will charge after the discount and included usage, which the billing API returns as pending_charged_micros. A reconciliation test holds the pill, Spend, Home and Usage to one number for one month. The usage and billing guide says how amounts are written and what this month means.3378 /// What of `pending_micros` the workspace will be charged when the
3379 /// month closes: its price less what g1t covers and what the discount
3380 /// takes off, as the close will enter it. Credit comes off at the close.
3381 #[serde(default)]
3382 pub pending_charged_micros: i64,
Usage, Billing settings and prepaid AI credit; fixes from the UX audit3383 /// What it cost g1t, before any markup.
3384 pub cost_micros: i64,
Spend adds up on one ledger. Charged this month has one definition, price less discount, included usage and credit, shared by the plan card, the spend limit, Spend and the top bar; the limit had counted usage not yet closed at full price before the discount, so a comped workspace read as charged a cent. Every agent line on the ledger names the agent and who asked, repository runs by g1t included, so Spent is the sum of its products, Agents is the agent product, and by agent adds up to it; the billing API returns by_agent and by_person. The usage and billing guide says how spend is counted.3385}
3386
Usage, Billing settings and prepaid AI credit; fixes from the UX audit3387/// One day's usage of one product, at price.
3388#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3389#[serde(rename_all = "camelCase")]
3390pub struct UsageDay {
3391 /// `YYYY-MM-DD`.
3392 pub day: String,
3393 pub product: String,
3394 pub micros: i64,
3395}
3396
3397/// How much of an allowance is used, in the meter's unit.
3398#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3399#[serde(rename_all = "camelCase")]
3400pub struct Allowance {
3401 pub used: f64,
3402 pub of: f64,
3403 /// `bytes`, `operations`, `dollars`…
3404 pub unit: String,
3405}
3406
3407/// One project's part of a meter.
3408#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3409#[serde(rename_all = "camelCase")]
3410pub struct ProjectUsage {
3411 /// `owner/name`, or empty for usage that is not one project's.
3412 pub project: String,
3413 pub micros: i64,
3414 pub quantity: f64,
3415}
3416
3417/// One meter over the range.
3418#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3419#[serde(rename_all = "camelCase")]
3420pub struct MeterLine {
3421 /// `agent_models`, `agent_rate`, `sandbox`, `builds`…
3422 pub key: String,
3423 pub label: String,
3424 pub product: String,
3425 /// What `quantity` counts: `tokens`, `seconds`, `bytes`, `operations`,
3426 /// `entries`.
3427 pub unit: String,
3428 pub quantity: f64,
3429 /// At price.
3430 pub micros: i64,
3431 /// Of `micros`, metered this month and charged when it closes.
3432 #[serde(default)]
3433 pub pending_micros: i64,
3434 /// Every day of the range, oldest first, at price: the sparkline.
3435 pub daily: Vec<i64>,
3436 #[serde(default)]
3437 pub allowance: Option<Allowance>,
3438 pub by_project: Vec<ProjectUsage>,
Merge branch 'model-routing'3439 /// How the quantity is counted, when that needs saying: for the agent
3440 /// rate, its tokens are weighted by kind, and this names the weights.
3441 #[serde(default)]
3442 pub note: Option<String>,
3443}
3444
Usage, Billing settings and prepaid AI credit; fixes from the UX audit3445/// One product family over the range.
3446#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3447#[serde(rename_all = "camelCase")]
3448pub struct ProductUsage {
3449 pub key: String,
3450 pub label: String,
3451 pub micros: i64,
3452 pub meters: Vec<MeterLine>,
3453}
3454
3455#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3456#[serde(rename_all = "camelCase")]
3457pub struct UsageReport {
3458 pub from: String,
3459 pub until: String,
3460 pub totals: UsageTotals,
3461 /// Each day and product with usage, oldest first.
3462 pub days: Vec<UsageDay>,
3463 /// Every product family, in order, even with nothing used.
3464 pub products: Vec<ProductUsage>,
3465 /// Every project with usage in the range, for the filter.
3466 pub projects: Vec<String>,
3467 /// The plan's included usage this month, when the workspace has it.
3468 #[serde(default)]
3469 pub included: Option<Allowance>,
3470 /// The account's discount, in percent, when it has one.
3471 #[serde(default)]
3472 pub discount_percent: Option<u32>,
The contracts no longer describe g1t's own agents, and workspaces can keep their AI providers. Every consumer had already stopped using them, so the TypeScript and Rust contracts drop the workspace-agent, ability, look, skill-library, context, runner-agent and mention modules, the chat and docs RPCs agents posted and read through, the folio agent methods, the agent_waiting notification, agent.asked and memory.changed events, AI credit, token and gateway billing types, model routes and sessions, team agents, agent tokens, plan, review, message and confidence types, command rules, cost caps and confidence rules. The agents:run and models:* scopes are no longer offered by any preset, OAuth default or permission form, but a stored token or grant that names them still reads; and the removed operations are gone from the scope table, so the API's check that every operation has exactly one scope is strict again. What stored data needs in order to parse (old run and credential kinds, an agent team lead, retired rules and webhook events, old guardrail and integration settings) still parses, and a run's token is still PrincipalKind::Agent, which now means a run's token and the @g1t rows written before. The customize, marketplace, skills and claude-plugin contracts stay only until the mobile app drops its Customize screens.3473 /// AI credit bought before g1t stopped selling it, left now (kept
3474 /// apart: it pays only for usage no longer offered), and credit from
3475 /// g1t for everything.
Usage, Billing settings and prepaid AI credit; fixes from the UX audit3476 pub ai_credit_micros: i64,
3477 pub credit_micros: i64,
3478 /// The trial credit left, for a workspace on its trial.
3479 #[serde(default)]
3480 pub trial_micros: Option<i64>,
3481 pub plan: PlanKind,
3482 /// Nothing is charged while g1t is being built out.
3483 pub free: bool,
3484}
3485
The contracts no longer describe g1t's own agents, and workspaces can keep their AI providers. Every consumer had already stopped using them, so the TypeScript and Rust contracts drop the workspace-agent, ability, look, skill-library, context, runner-agent and mention modules, the chat and docs RPCs agents posted and read through, the folio agent methods, the agent_waiting notification, agent.asked and memory.changed events, AI credit, token and gateway billing types, model routes and sessions, team agents, agent tokens, plan, review, message and confidence types, command rules, cost caps and confidence rules. The agents:run and models:* scopes are no longer offered by any preset, OAuth default or permission form, but a stored token or grant that names them still reads; and the removed operations are gone from the scope table, so the API's check that every operation has exactly one scope is strict again. What stored data needs in order to parse (old run and credential kinds, an agent team lead, retired rules and webhook events, old guardrail and integration settings) still parses, and a run's token is still PrincipalKind::Agent, which now means a run's token and the @g1t rows written before. The customize, marketplace, skills and claude-plugin contracts stay only until the mobile app drops its Customize screens.3486// --- Card fee -------------------------------------------------------------------
Usage, Billing settings and prepaid AI credit; fixes from the UX audit3487
The contracts no longer describe g1t's own agents, and workspaces can keep their AI providers. Every consumer had already stopped using them, so the TypeScript and Rust contracts drop the workspace-agent, ability, look, skill-library, context, runner-agent and mention modules, the chat and docs RPCs agents posted and read through, the folio agent methods, the agent_waiting notification, agent.asked and memory.changed events, AI credit, token and gateway billing types, model routes and sessions, team agents, agent tokens, plan, review, message and confidence types, command rules, cost caps and confidence rules. The agents:run and models:* scopes are no longer offered by any preset, OAuth default or permission form, but a stored token or grant that names them still reads; and the removed operations are gone from the scope table, so the API's check that every operation has exactly one scope is strict again. What stored data needs in order to parse (old run and credential kinds, an agent team lead, retired rules and webhook events, old guardrail and integration settings) still parses, and a run's token is still PrincipalKind::Agent, which now means a run's token and the @g1t rows written before. The customize, marketplace, skills and claude-plugin contracts stay only until the mobile app drops its Customize screens.3488/// The card fee passed on when a payment is made by card.
Usage, Billing settings and prepaid AI credit; fixes from the UX audit3489#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
3490#[serde(rename_all = "camelCase")]
3491pub struct CardFee {
3492 pub on: bool,
3493 /// Per dollar charged, in millionths: 29,000 is 2.9%.
3494 pub percent_micros: f64,
3495 pub fixed_cents: u32,
3496}
3497
3498// --- Budgets ------------------------------------------------------------------
3499
3500/// `set_budget`: the monthly budget on usage after included usage: the
3501/// owners' spend limit, its alerts, whether usage pauses at 100%, and an
3502/// optional webhook. Owners only. Returns `Outcome<Limit>`.
3503#[derive(Debug, Serialize, Deserialize)]
3504#[serde(rename_all = "camelCase")]
3505pub struct SetBudgetArgs {
3506 pub actor: User,
3507 pub workspace: String,
3508 /// The amount; None keeps the automatic one.
3509 #[serde(default, alias = "amount_micros")]
3510 pub amount_micros: Option<i64>,
3511 /// Some of 50, 75, 90 and 100.
3512 #[serde(default)]
3513 pub alerts: Vec<u32>,
3514 #[serde(default = "yes", alias = "pause_at_limit")]
3515 pub pause_at_limit: bool,
3516 /// An HTTPS address, or None for no webhook.
3517 #[serde(default)]
3518 pub webhook: Option<String>,
3519 /// Leave the spend limit as it is and change only the alerts, the
3520 /// pause and the webhook.
3521 #[serde(default, alias = "keep_limit")]
3522 pub keep_limit: bool,
3523}
3524
3525// --- Billing details -----------------------------------------------------------
3526
3527/// A postal address, as Stripe keeps it.
3528#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
3529#[serde(rename_all = "camelCase")]
3530pub struct PostalAddress {
3531 #[serde(default)]
3532 pub line1: String,
3533 #[serde(default)]
3534 pub line2: String,
3535 #[serde(default)]
3536 pub city: String,
3537 #[serde(default)]
3538 pub state: String,
3539 #[serde(default)]
3540 pub postal_code: String,
3541 /// Two letters, `US`.
3542 #[serde(default)]
3543 pub country: String,
3544}
3545
3546/// The default way the workspace pays, as far as it is safe to show.
3547#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3548#[serde(rename_all = "camelCase")]
3549pub struct PaymentMethod {
3550 /// `card`, or another kind Stripe has.
3551 pub kind: String,
3552 #[serde(default)]
3553 pub brand: Option<String>,
3554 #[serde(default)]
3555 pub last4: Option<String>,
3556 #[serde(default)]
3557 pub exp_month: Option<u32>,
3558 #[serde(default)]
3559 pub exp_year: Option<u32>,
3560}
3561
3562/// One of the customer's invoices at Stripe: the plan, activations, AI
3563/// credit and month-end usage.
3564#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3565#[serde(rename_all = "camelCase")]
3566pub struct StripeInvoice {
3567 pub id: String,
3568 #[serde(default)]
3569 pub number: Option<String>,
3570 /// `paid`, `open`, `void`, `uncollectible` or `draft`.
3571 pub status: String,
3572 pub total_cents: i64,
3573 pub currency: String,
3574 /// RFC 3339.
3575 pub created_at: String,
3576 #[serde(default)]
3577 pub description: Option<String>,
3578 #[serde(default)]
3579 pub hosted_url: Option<String>,
3580 #[serde(default)]
3581 pub pdf_url: Option<String>,
3582}
3583
3584/// What the next invoice will be, from g1t's own ledger.
3585#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
3586#[serde(rename_all = "camelCase")]
3587pub struct UpcomingInvoice {
3588 /// When the month closes, RFC 3339.
3589 pub closes_at: String,
3590 /// The plan and activations, at their monthly price.
3591 pub subscriptions_micros: i64,
3592 /// Usage still owed, after included usage, credit and any discount.
3593 pub usage_micros: i64,
3594 pub total_micros: i64,
3595}
3596
3597/// `billing_details` (`AccountArgs`): who the invoices are for, the default
3598/// payment method, and the invoices, from the Stripe customer. Members see
3599/// it; owners change it. Returns `Outcome<BillingDetails>`.
3600#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
3601#[serde(rename_all = "camelCase")]
3602pub struct BillingDetails {
3603 /// Whether the workspace has a Stripe customer yet.
3604 pub customer: bool,
3605 pub email: Option<String>,
3606 pub name: Option<String>,
3607 pub address: Option<PostalAddress>,
3608 /// `eu_vat`, `us_ein`…, and its value.
3609 pub tax_id_type: Option<String>,
3610 pub tax_id: Option<String>,
3611 /// Printed on invoices.
3612 pub po_number: Option<String>,
3613 /// The invoices' language, such as `en` or `fr`.
3614 pub language: Option<String>,
3615 pub payment_method: Option<PaymentMethod>,
3616 pub invoices: Vec<StripeInvoice>,
3617 pub upcoming: UpcomingInvoice,
3618 /// Stripe could not be read: what is shown is what g1t keeps.
3619 #[serde(default)]
3620 pub unavailable: Option<String>,
Merge Stripe Tax, the card fee on card payments, and one free workspace per person3621 /// Whether Stripe Tax can place the customer from the address: tax
3622 /// is worked out from it, and without it nothing is charged.
3623 #[serde(default)]
3624 pub tax_location: bool,
3625 /// Set when g1t did not charge for want of an address (RFC 3339).
3626 #[serde(default)]
3627 pub tax_address_needed_at: Option<String>,
3628 /// Stripe's check of the tax ID: `pending`, `verified`, `unverified` or
3629 /// `unavailable`.
3630 #[serde(default)]
3631 pub tax_id_status: Option<String>,
3632 /// `none`, `exempt` or `reverse`, as staff set it at Stripe; g1t never
3633 /// changes it.
3634 #[serde(default)]
3635 pub tax_exempt: Option<String>,
Usage, Billing settings and prepaid AI credit; fixes from the UX audit3636}
3637
3638/// `set_billing_details`: saves the invoice details on the Stripe customer.
3639/// Owners only. Absent fields are left as they are; an empty string clears
3640/// one. Returns `Outcome<BillingDetails>`.
3641#[derive(Debug, Serialize, Deserialize)]
3642#[serde(rename_all = "camelCase")]
3643pub struct SetBillingDetailsArgs {
3644 pub actor: User,
3645 pub workspace: String,
3646 #[serde(default)]
3647 pub email: Option<String>,
3648 #[serde(default)]
3649 pub name: Option<String>,
3650 #[serde(default)]
3651 pub address: Option<PostalAddress>,
3652 #[serde(default, alias = "tax_id_type")]
3653 pub tax_id_type: Option<String>,
3654 #[serde(default, alias = "tax_id")]
3655 pub tax_id: Option<String>,
3656 #[serde(default, alias = "po_number")]
3657 pub po_number: Option<String>,
3658 #[serde(default)]
3659 pub language: Option<String>,
3660}
3661
Mission control counts people's direct pushes to the default branch3662#[cfg(test)]
3663mod tests {
3664 use super::*;
3665
3666 #[test]
3667 fn an_account_carries_no_run_fee() {
3668 let account = Account {
3669 workspace: "acme".into(),
3670 balance_micros: 0,
3671 status: Status { enabled: true, live: false, free: false },
3672 margin_percent: 20,
3673 card: None,
3674 };
3675 let json = serde_json::to_value(account).unwrap();
3676 let mut keys: Vec<&str> = json.as_object().unwrap().keys().map(String::as_str).collect();
3677 keys.sort_unstable();
3678 assert_eq!(keys, ["balanceMicros", "card", "marginPercent", "status", "workspace"]);
3679 }
3680
3681 #[test]
3682 fn a_price_change_says_when_the_markup_moved() {
3683 let change = PriceChange {
3684 meter: "sandbox_second".into(),
3685 old_cost_micros: 21.0,
3686 new_cost_micros: 21.0,
3687 markup_percent: 20,
3688 old_markup_percent: Some(138),
3689 reason: "Sandbox time is now charged at cost plus 20% from the first second".into(),
3690 created_at: "2026-10-05T00:00:00Z".into(),
3691 effective_at: None,
3692 };
3693 assert_eq!(serde_json::to_value(&change).unwrap()["oldMarkupPercent"], 138);
3694 let cost_only = PriceChange { old_markup_percent: None, ..change };
3695 assert!(serde_json::to_value(&cost_only).unwrap().get("oldMarkupPercent").is_none());
3696 }
3697
3698 #[test]
3699 fn features_are_named_as_the_site_sends_them() {
3700 assert_eq!(
3701 serde_json::to_value(Feature::Deployments).unwrap(),
3702 serde_json::json!("deployments")
3703 );
3704 assert_eq!(Feature::parse("deployments"), Some(Feature::Deployments));
3705 assert_eq!(serde_json::to_value(Feature::Plan).unwrap(), serde_json::json!("plan"));
3706 assert_eq!(Feature::parse("plan"), Some(Feature::Plan));
3707 // Older readers named the plan Team.
3708 assert_eq!(Feature::parse("team"), Some(Feature::Plan));
3709 assert_eq!(serde_json::from_value::<Feature>(serde_json::json!("team")).unwrap(), Feature::Plan);
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar3710 assert_eq!(Feature::ALL, [Feature::Plan, Feature::Security]);
3711 assert_eq!(Feature::parse("security"), Some(Feature::Security));
3712 assert_eq!(serde_json::to_value(Feature::Security).unwrap(), serde_json::json!("security"));
Mission control counts people's direct pushes to the default branch3713 assert!(SubscriptionStatus::Canceling.on());
3714 assert!(!SubscriptionStatus::PastDue.on());
3715 }
3716
3717 #[test]
3718 fn a_reservation_is_asked_for_and_answered_in_camel_case() {
3719 let asked: ReserveArgs = serde_json::from_value(serde_json::json!({
3720 "workspace": "acme",
3721 "repo": { "namespace": "acme", "name": "web" },
3722 "public": true,
3723 "kind": "check",
3724 "estimateMicros": 2_000_000,
3725 }))
3726 .unwrap();
3727 assert_eq!(asked.kind, ComputeKind::Check);
3728 assert!(asked.kind.open_source_pool());
The contracts no longer describe g1t's own agents, and workspaces can keep their AI providers. Every consumer had already stopped using them, so the TypeScript and Rust contracts drop the workspace-agent, ability, look, skill-library, context, runner-agent and mention modules, the chat and docs RPCs agents posted and read through, the folio agent methods, the agent_waiting notification, agent.asked and memory.changed events, AI credit, token and gateway billing types, model routes and sessions, team agents, agent tokens, plan, review, message and confidence types, command rules, cost caps and confidence rules. The agents:run and models:* scopes are no longer offered by any preset, OAuth default or permission form, but a stored token or grant that names them still reads; and the removed operations are gone from the scope table, so the API's check that every operation has exactly one scope is strict again. What stored data needs in order to parse (old run and credential kinds, an agent team lead, retired rules and webhook events, old guardrail and integration settings) still parses, and a run's token is still PrincipalKind::Agent, which now means a run's token and the @g1t rows written before. The customize, marketplace, skills and claude-plugin contracts stay only until the mobile app drops its Customize screens.3729 assert!(!ComputeKind::Deploy.open_source_pool());
3730 // Retired kinds still parse from stored rows.
3731 let stored: ComputeKind = serde_json::from_value(serde_json::json!("agent")).unwrap();
3732 assert_eq!(stored, ComputeKind::Agent);
Mission control counts people's direct pushes to the default branch3733 // Rust callers that write snake_case are read too.
3734 let snake: ReserveArgs = serde_json::from_value(serde_json::json!({
3735 "workspace": "acme",
3736 "repo": { "namespace": "acme", "name": "web" },
3737 "public": false,
The contracts no longer describe g1t's own agents, and workspaces can keep their AI providers. Every consumer had already stopped using them, so the TypeScript and Rust contracts drop the workspace-agent, ability, look, skill-library, context, runner-agent and mention modules, the chat and docs RPCs agents posted and read through, the folio agent methods, the agent_waiting notification, agent.asked and memory.changed events, AI credit, token and gateway billing types, model routes and sessions, team agents, agent tokens, plan, review, message and confidence types, command rules, cost caps and confidence rules. The agents:run and models:* scopes are no longer offered by any preset, OAuth default or permission form, but a stored token or grant that names them still reads; and the removed operations are gone from the scope table, so the API's check that every operation has exactly one scope is strict again. What stored data needs in order to parse (old run and credential kinds, an agent team lead, retired rules and webhook events, old guardrail and integration settings) still parses, and a run's token is still PrincipalKind::Agent, which now means a run's token and the @g1t rows written before. The customize, marketplace, skills and claude-plugin contracts stay only until the mobile app drops its Customize screens.3738 "kind": "deploy",
Mission control counts people's direct pushes to the default branch3739 "estimate_micros": 1,
3740 }))
3741 .unwrap();
3742 assert_eq!(snake.estimate_micros, 1);
3743 let answer = Reservation { id: "rsv_1".into(), paid_by: PaidBy::OnDemand, held_micros: 5, expires_at: String::new() };
3744 assert_eq!(serde_json::to_value(&answer).unwrap()["paidBy"], "on_demand");
3745 assert_eq!(serde_json::to_value(PlanKind::Internal).unwrap(), "internal");
3746 assert!(!PlanKind::Free.on_demand() && PlanKind::Enterprise.on_demand());
3747 }
3748
3749 #[test]
3750 fn a_refusal_carries_its_own_code() {
3751 let refused: crate::Outcome<Reservation> =
3752 crate::Outcome::fail(crate::FailureCode::OssPoolEmpty, "The open-source pool is spent.");
3753 let json = serde_json::to_value(&refused).unwrap();
3754 assert_eq!(json["error"]["code"], "oss_pool_empty");
3755 assert_eq!(crate::FailureCode::NotPaid.http_status(), 402);
3756 assert_eq!(crate::FailureCode::Paused.http_status(), 409);
3757 }
3758}

This file's history is long; its oldest lines are credited to the oldest commit read.