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 running | 3 | //! |
| 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 running | 6 | //! |
| 7 | //! Each `*Args` struct is the argument of the method of the same name, | |
| 8 | //! served at `POST /rpc/<method>`. | |
| 9 | ||
| 10 | use serde::{Deserialize, Serialize}; | |
| 11 | ||
| 12 | use crate::repos::RepoPath; | |
| 13 | use crate::{User, Viewer}; | |
| 14 | ||
| 15 | /// Millionths of a US dollar in one dollar. | |
| 16 | pub 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)] | |
| 21 | pub 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")] | |
| 44 | pub 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")] | |
| 54 | pub 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")] | |
| 81 | pub 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")] | |
| 98 | pub 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)] | |
| 112 | pub 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)] | |
| 121 | pub struct AdminBillingLinkArgs { | |
| 122 | pub workspace: String, | |
| 123 | pub by: String, | |
| 124 | } | |
| 125 | ||
| 126 | #[derive(Clone, Debug, Serialize, Deserialize)] | |
| 127 | #[serde(rename_all = "camelCase")] | |
| 128 | pub 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")] | |
| 140 | pub 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")] | |
| 150 | pub 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 charging | 191 | /// 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 running | 199 | } |
| 200 | ||
| 201 | fn 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)] | |
| 208 | pub 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")] | |
| 220 | pub 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)] | |
| 235 | pub 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)] | |
| 243 | pub 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)] | |
| 253 | pub 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")] | |
| 263 | pub 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")] | |
| 272 | pub 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 charging | 281 | /// 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 audit | 289 | /// 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 running | 295 | /// 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 tokens | 319 | } |
| 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 running | 321 | /// 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")] | |
| 332 | pub 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 bar | 343 | 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 running | 344 | } |
| 345 | ||
| 346 | impl Feature { | |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 347 | /// 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 running | 349 | |
| 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 bar | 354 | 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 running | 355 | } |
| 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 bar | 362 | "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 running | 363 | _ => 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 bar | 371 | 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 running | 372 | } |
| 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. | |
| 383 | pub 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 running | 396 | /// 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 running | 409 | } |
| 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 running | 418 | /// instead. |
| 419 | /// Returns `Outcome<bool>`: false if that reference was recorded before. | |
| 420 | #[derive(Debug, Serialize, Deserialize)] | |
| 421 | #[serde(rename_all = "camelCase")] | |
| 422 | pub 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 running | 432 | /// 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 running | 452 | #[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")] | |
| 460 | pub 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")] | |
| 476 | pub 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")] | |
| 491 | pub 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 running | 519 | #[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 audit | 551 | /// 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 running | 562 | } |
| 563 | ||
| Usage, Billing settings and prepaid AI credit; fixes from the UX audit | 564 | fn 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 running | 568 | /// `limit`: a workspace's limit, for its members. Returns `Outcome<Limit>`. |
| 569 | #[derive(Debug, Serialize, Deserialize)] | |
| 570 | pub 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)] | |
| 578 | pub 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")] | |
| 588 | pub 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)] | |
| 608 | pub 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")] | |
| 616 | pub 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")] | |
| 634 | pub 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")] | |
| 653 | pub 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 | ||
| 670 | impl 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")] | |
| 679 | pub 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")] | |
| 700 | pub 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")] | |
| 718 | pub 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")] | |
| 758 | pub 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")] | |
| 781 | pub 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)] | |
| 819 | pub 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. | |
| 846 | pub 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. | |
| 849 | pub 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")] | |
| 854 | pub 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 | ||
| 867 | impl 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")] | |
| 886 | pub 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 running | 889 | 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 running | 900 | Embedding, |
| 901 | } | |
| 902 | ||
| 903 | impl 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")] | |
| 926 | pub 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)] | |
| 941 | pub 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)] | |
| 949 | pub struct AuditRetentionArgs { | |
| 950 | pub workspaces: Vec<String>, | |
| 951 | } | |
| 952 | ||
| 953 | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | |
| 954 | pub struct AuditRetention { | |
| 955 | pub workspace: String, | |
| 956 | pub days: u32, | |
| 957 | } | |
| 958 | ||
| 959 | #[derive(Clone, Debug, Serialize, Deserialize)] | |
| 960 | #[serde(rename_all = "camelCase")] | |
| 961 | pub 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 running | 1003 | // 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")] | |
| 1061 | pub 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")] | |
| 1075 | pub 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")] | |
| 1108 | pub 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 running | 1118 | #[serde(alias = "estimate_micros")] |
| 1119 | pub estimate_micros: i64, | |
| 1120 | } | |
| 1121 | ||
| 1122 | #[derive(Clone, Debug, Serialize, Deserialize)] | |
| 1123 | #[serde(rename_all = "camelCase")] | |
| 1124 | pub 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")] | |
| 1141 | pub 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")] | |
| 1159 | pub 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)] | |
| 1170 | pub 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")] | |
| 1182 | pub 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")] | |
| 1212 | pub 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)] | |
| 1227 | pub 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")] | |
| 1238 | pub 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")] | |
| 1251 | pub 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")] | |
| 1263 | pub 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")] | |
| 1286 | pub 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)] | |
| 1294 | pub 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)] | |
| 1304 | pub 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)] | |
| 1321 | pub 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")] | |
| 1336 | pub 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")] | |
| 1352 | pub 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)] | |
| 1375 | pub 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)] | |
| 1383 | pub 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")] | |
| 1399 | pub 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)] | |
| 1415 | pub struct AdminVelocityArgs {} | |
| 1416 | ||
| 1417 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] | |
| 1418 | #[serde(rename_all = "snake_case")] | |
| 1419 | pub 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")] | |
| 1427 | pub 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 | ||
| 1447 | impl 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 charging | 1460 | /// 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 running | 1478 | /// 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 charging | 1480 | 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 running | 1481 | } |
| 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 charging | 1484 | /// 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 charging | 1490 | (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 running | 1501 | } |
| 1502 | ||
| 1503 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] | |
| 1504 | #[serde(rename_all = "snake_case")] | |
| 1505 | pub enum TermsKind { | |
| 1506 | /// Prices as published, limits by trust. | |
| 1507 | Standard, | |
| Billing: credits with a kind and expiry, discounts instead of comped, and safer charging | 1508 | /// 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 running | 1510 | Comped, |
| Billing: credits with a kind and expiry, discounts instead of comped, and safer charging | 1511 | /// 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 running | 1512 | 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)] | |
| 1520 | pub 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)] | |
| 1529 | pub 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")] | |
| 1538 | pub 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")] | |
| 1555 | pub 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")] | |
| 1566 | pub 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)] | |
| 1576 | pub 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 person | 1582 | /// `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")] | |
| 1588 | pub 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 running | 1598 | /// `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)] | |
| 1602 | pub 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")] | |
| 1610 | pub 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")] | |
| 1624 | pub 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")] | |
| 1634 | pub 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 person | 1647 | /// 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 running | 1654 | } |
| 1655 | ||
| 1656 | #[derive(Clone, Debug, Serialize, Deserialize)] | |
| 1657 | #[serde(rename_all = "camelCase")] | |
| 1658 | pub 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)] | |
| 1666 | pub 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)] | |
| 1674 | pub 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)] | |
| 1682 | pub 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")] | |
| 1695 | pub 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")] | |
| 1705 | pub 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 charging | 1712 | /// 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 running | 1717 | } |
| 1718 | ||
| 1719 | #[derive(Clone, Debug, Serialize, Deserialize)] | |
| 1720 | #[serde(rename_all = "camelCase")] | |
| 1721 | pub 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 charging | 1734 | /// 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 person | 1741 | /// 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 running | 1750 | } |
| 1751 | ||
| 1752 | #[derive(Clone, Debug, Serialize, Deserialize)] | |
| 1753 | #[serde(rename_all = "camelCase")] | |
| 1754 | pub 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 charging | 1759 | /// 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 running | 1768 | /// 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 person | 1776 | /// 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 running | 1782 | } |
| 1783 | ||
| 1784 | /// One source that paid for usage before it was charged. | |
| 1785 | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | |
| 1786 | #[serde(rename_all = "camelCase")] | |
| 1787 | pub 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)] | |
| 1799 | pub 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")] | |
| 1821 | pub 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")] | |
| 1843 | pub 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)] | |
| 1863 | pub 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")] | |
| 1874 | pub 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)] | |
| 1894 | pub 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)] | |
| 1907 | pub struct AdminSignalsArgs {} | |
| 1908 | ||
| 1909 | /// What staff are doing about a workspace. | |
| 1910 | #[derive(Clone, Debug, Serialize, Deserialize)] | |
| 1911 | #[serde(rename_all = "camelCase")] | |
| 1912 | pub 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")] | |
| 1927 | pub 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)] | |
| 1936 | pub 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)] | |
| 1942 | pub 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)] | |
| 1956 | pub 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)] | |
| 1964 | pub struct AdminOverviewArgs {} | |
| 1965 | ||
| 1966 | #[derive(Clone, Debug, Serialize, Deserialize)] | |
| 1967 | #[serde(rename_all = "camelCase")] | |
| 1968 | pub 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")] | |
| 2015 | pub 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")] | |
| 2027 | pub 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")] | |
| 2038 | pub 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")] | |
| 2054 | pub 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)] | |
| 2069 | pub 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")] | |
| 2080 | pub 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")] | |
| 2101 | pub 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")] | |
| 2122 | pub 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)] | |
| 2131 | pub 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")] | |
| 2138 | pub 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)] | |
| 2148 | pub 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)] | |
| 2156 | pub 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)] | |
| 2165 | pub 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 charging | 2171 | /// 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")] | |
| 2174 | pub 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 | ||
| 2190 | impl 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 running | 2225 | #[derive(Debug, Serialize, Deserialize)] |
| 2226 | pub 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 charging | 2231 | #[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")] | |
| 2248 | pub 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")] | |
| 2289 | pub 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)] | |
| 2298 | pub 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")] | |
| 2315 | pub 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")] | |
| 2327 | pub 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)] | |
| 2339 | pub 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 running | 2343 | } |
| 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's | 2345 | /// `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)] | |
| 2350 | pub 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")] | |
| 2360 | pub 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 sold | 2363 | /// 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's | 2367 | } |
| 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 running | 2369 | /// One change made in sudo. |
| 2370 | #[derive(Clone, Debug, Serialize, Deserialize)] | |
| 2371 | #[serde(rename_all = "camelCase")] | |
| 2372 | pub 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")] | |
| 2384 | pub struct Plan { | |
| 2385 | pub feature: Feature, | |
| 2386 | pub title: String, | |
| Merge Stripe Tax, the card fee on card payments, and one free workspace per person | 2387 | /// 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 running | 2388 | pub monthly_cents: u32, |
| Merge Stripe Tax, the card fee on card payments, and one free workspace per person | 2389 | /// 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 running | 2393 | /// 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")] | |
| 2401 | pub 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 | ||
| 2412 | impl 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")] | |
| 2422 | pub 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")] | |
| 2438 | pub 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)] | |
| 2452 | pub 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")] | |
| 2462 | pub 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)] | |
| 2473 | pub 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)] | |
| 2483 | pub 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")] | |
| 2502 | pub 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)] | |
| 2513 | pub 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)] | |
| 2526 | pub 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 person | 2531 | /// `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)] | |
| 2538 | pub 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 running | 2542 | /// `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")] | |
| 2549 | pub 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)] | |
| 2573 | pub 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")] | |
| 2582 | pub 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")] | |
| 2599 | pub 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")] | |
| 2620 | pub 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 charging | 2663 | /// 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-a69aeabc4b0deeb97 | 2670 | /// 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 charging | 2679 | /// 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 running | 2687 | /// `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 running | 2695 | #[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 person | 2699 | /// 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 running | 2717 | } |
| 2718 | ||
| 2719 | /// A count, cost or leak that does not add up. | |
| 2720 | #[derive(Clone, Debug, Serialize, Deserialize)] | |
| 2721 | #[serde(rename_all = "camelCase")] | |
| 2722 | pub 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 running | 2730 | 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")] | |
| 2741 | pub 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")] | |
| 2756 | pub 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")] | |
| 2783 | pub 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 rises | 2795 | /// 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 running | 2802 | } |
| 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")] | |
| 2808 | pub 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")] | |
| 2822 | pub 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")] | |
| 2837 | pub 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")] | |
| 2853 | pub 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 person | 2869 | /// 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 audit | 2874 | #[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 running | 2876 | } |
| 2877 | ||
| 2878 | impl 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 audit | 2889 | 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 running | 2890 | } |
| 2891 | } | |
| 2892 | } | |
| 2893 | ||
| 2894 | /// The Costs & margin page. | |
| 2895 | #[derive(Clone, Debug, Default, Serialize, Deserialize)] | |
| 2896 | #[serde(rename_all = "camelCase")] | |
| 2897 | pub 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 running | 2931 | } |
| 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")] | |
| 2937 | pub 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")] | |
| 2957 | pub 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")] | |
| 2978 | pub 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 running | 2992 | /// 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 & pricing | 2994 | /// 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")] | |
| 2997 | pub 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 running | 3002 | /// 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")] | |
| 3005 | pub 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 running | 3016 | /// 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 & pricing | 3031 | /// 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 running | 3033 | 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 & pricing | 3034 | /// `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 running | 3046 | /// 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 rises | 3048 | /// 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 running | 3057 | } |
| 3058 | ||
| 3059 | #[derive(Clone, Debug, Default, Serialize, Deserialize)] | |
| 3060 | #[serde(rename_all = "camelCase")] | |
| 3061 | pub 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")] | |
| 3070 | pub 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)] | |
| 3084 | pub 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 running | 3087 | /// of today (UTC), with why. Recorded in the audit log. Returns |
| 3088 | /// `Outcome<SpendCaps>`. | |
| 3089 | #[derive(Debug, Serialize, Deserialize)] | |
| 3090 | pub 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")] | |
| 3102 | pub 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 | ||
| 3115 | impl 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)] | |
| 3136 | pub 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 | ||
| 3147 | impl 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)] | |
| 3173 | pub 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)] | |
| 3185 | pub 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)] | |
| 3198 | pub 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)] | |
| 3218 | pub 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)] | |
| 3245 | pub 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)] | |
| 3253 | pub 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)] | |
| 3258 | pub 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 running | 3265 | /// `admin_cost_alerts`: the open margin alerts, for sudo's banner. |
| 3266 | /// Returns `Vec<MarginAlert>`. | |
| 3267 | #[derive(Debug, Default, Serialize, Deserialize)] | |
| 3268 | pub 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)] | |
| 3274 | pub 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)] | |
| 3285 | pub 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)] | |
| 3293 | pub 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)] | |
| 3316 | pub struct AdminRunCostsArgs { | |
| 3317 | #[serde(default)] | |
| 3318 | pub by: String, | |
| 3319 | } | |
| 3320 | ||
| 3321 | #[derive(Clone, Debug, Default, Serialize, Deserialize)] | |
| 3322 | #[serde(rename_all = "camelCase")] | |
| 3323 | pub 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 audit | 3332 | // --- 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. | 3336 | pub const PRODUCTS: [(&str, &str); 6] = [ |
| Usage, Billing settings and prepaid AI credit; fixes from the UX audit | 3337 | ("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")] | |
| 3351 | pub 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")] | |
| 3371 | pub 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 audit | 3391 | /// 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 audit | 3395 | /// One day's usage of one product, at price. |
| 3396 | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | |
| 3397 | #[serde(rename_all = "camelCase")] | |
| 3398 | pub 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")] | |
| 3408 | pub 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")] | |
| 3418 | pub 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")] | |
| 3428 | pub 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 audit | 3453 | /// One product family over the range. |
| 3454 | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | |
| 3455 | #[serde(rename_all = "camelCase")] | |
| 3456 | pub 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")] | |
| 3465 | pub 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 audit | 3484 | 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 audit | 3495 | |
| 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 audit | 3497 | #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] |
| 3498 | #[serde(rename_all = "camelCase")] | |
| 3499 | pub 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")] | |
| 3513 | pub 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")] | |
| 3538 | pub 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")] | |
| 3557 | pub 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")] | |
| 3574 | pub 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")] | |
| 3595 | pub 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")] | |
| 3610 | pub 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 person | 3629 | /// 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 audit | 3644 | } |
| 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")] | |
| 3651 | pub 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 running | 3670 | #[cfg(test)] |
| 3671 | mod 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 bar | 3718 | 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 running | 3721 | 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 running | 3741 | // 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 running | 3747 | "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.