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

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