Skip to content

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

g1t.sh
276 linesCodeBlameRaw

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

Billing, integrations, security and identity no longer serve g1t's own agents. Billing stops metering agent runs, model tokens and AI Gateway requests, drops its model catalogue and price-keeper model prices, and stops selling AI credit, which only ever paid for those; credit bought earlier still pays toward what is owed. A usage report, statement or invoice that holds an old agent or model meter shows it as "Other usage" rather than failing, and the get_ai_credit and buy_ai_credit API operations and MCP billing actions go. Integrations no longer connects model providers or routes models, and no longer assigns imported issues or alerts to g1t; a model provider already connected can still be disconnected. Security drops "Fix with g1t". Identity no longer creates agent tokens or puts agents on teams, a team's lead is a person, and run credentials are issued only for checks, the merge queue, merge checks, deployments and bumps; tokens and credentials already issued keep working until they expire. The reserved names g1t and g1t-agent stay reserved. No tables are dropped.1//! Run credentials: a token per sandbox run (checks, the merge queue, a
2//! merge check, a deployment or a security update's bump), bound to the
3//! run, its repository and what its kind of work needs, acting as g1t on
4//! behalf of the person who started the work, or of the workspace for
5//! g1t's own. See `g1t_contracts::credentials` for the policy.
6//!
7//! Credentials made for agent runs before g1t stopped running agents keep
8//! resolving until they expire (at most six hours), so nothing in flight
9//! breaks; no new ones are made.
README: run the core forge locally with Docker Compose; forks described as copies, not copy-on-write, until Cloudflare says otherwise10
11use g1t_contracts::credentials::{
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.12 Acting, BindRunCredentialsArgs, CreateRunCredentialArgs, CredentialUse, Principal, RevokeRunCredentialsArgs,
Billing, integrations, security and identity no longer serve g1t's own agents. Billing stops metering agent runs, model tokens and AI Gateway requests, drops its model catalogue and price-keeper model prices, and stops selling AI credit, which only ever paid for those; credit bought earlier still pays toward what is owed. A usage report, statement or invoice that holds an old agent or model meter shows it as "Other usage" rather than failing, and the get_ai_credit and buy_ai_credit API operations and MCP billing actions go. Integrations no longer connects model providers or routes models, and no longer assigns imported issues or alerts to g1t; a model provider already connected can still be disconnected. Security drops "Fix with g1t". Identity no longer creates agent tokens or puts agents on teams, a team's lead is a person, and run credentials are issued only for checks, the merge queue, merge checks, deployments and bumps; tokens and credentials already issued keep working until they expire. The reserved names g1t and g1t-agent stay reserved. No tables are dropped.13 RunBinding, RunCredentialKind, intersect, intersect_grants, operations_for,
README: run the core forge locally with Docker Compose; forks described as copies, not copy-on-write, until Cloudflare says otherwise14};
15use g1t_contracts::identity::{
16 AGENT_ID, AGENT_NAME, AgentScope, CreateAccessTokenArgs, CreatedAccessToken,
17};
18use g1t_contracts::time::SQL_NOW;
19use g1t_contracts::{PrincipalKind, User, Viewer};
20use worker::Result;
21use worker::wasm_bindgen::JsValue;
22
23use crate::Identity;
24
25/// No run outlives this, whatever its caller asks for.
26const MAX_RUN_TTL_SECONDS: u64 = 6 * 60 * 60;
27const MIN_RUN_TTL_SECONDS: u64 = 60;
28/// More hashes than one sandbox ever holds.
29const MAX_HASHES: usize = 8;
30
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.31/// Whether a credential is still made for this kind of run and use: a
32/// runner's, for sandbox work that is not one of the retired hosted
33/// agents' (`RunCredentialKind::retired`).
34fn issued_for(kind: RunCredentialKind, usage: CredentialUse) -> bool {
35 !kind.retired() && usage == CredentialUse::Runner
Billing, integrations, security and identity no longer serve g1t's own agents. Billing stops metering agent runs, model tokens and AI Gateway requests, drops its model catalogue and price-keeper model prices, and stops selling AI credit, which only ever paid for those; credit bought earlier still pays toward what is owed. A usage report, statement or invoice that holds an old agent or model meter shows it as "Other usage" rather than failing, and the get_ai_credit and buy_ai_credit API operations and MCP billing actions go. Integrations no longer connects model providers or routes models, and no longer assigns imported issues or alerts to g1t; a model provider already connected can still be disconnected. Security drops "Fix with g1t". Identity no longer creates agent tokens or puts agents on teams, a team's lead is a person, and run credentials are issued only for checks, the merge queue, merge checks, deployments and bumps; tokens and credentials already issued keep working until they expire. The reserved names g1t and g1t-agent stay reserved. No tables are dropped.36}
37
README: run the core forge locally with Docker Compose; forks described as copies, not copy-on-write, until Cloudflare says otherwise38/// A SHA-256 in lowercase hex, as tokens are stored.
39fn is_hash(value: &str) -> bool {
40 value.len() == 64
41 && value
42 .bytes()
43 .all(|b| b.is_ascii_digit() || (b'a'..=b'f').contains(&b))
44}
45
46impl Identity {
47 /// The composite identity behind an agent's token: the agent, acting
48 /// for the person (or workspace) the token was made for, in the run's
49 /// workspace only, and only while that person still belongs to it.
50 pub(crate) async fn agent_principal(
51 &self,
52 credential_id: &str,
53 user_id: Option<&str>,
54 workspace_id: Option<&str>,
55 scope: AgentScope,
56 ) -> Result<Viewer> {
57 let person = match (user_id, workspace_id) {
58 (Some(id), _) => {
59 self.find_user(
60 "SELECT id, username, email_verified_at IS NOT NULL AS verified
Merge account deletion: soft delete for 30 days, staff restore and purge, ghost for what remains (identity 0037)61 FROM users WHERE id = ? AND deleted_at IS NULL",
README: run the core forge locally with Docker Compose; forks described as copies, not copy-on-write, until Cloudflare says otherwise62 id,
63 )
64 .await?
65 }
66 (None, Some(id)) => self.workspace_principal(id).await?,
67 (None, None) => None,
68 };
69 // The person is gone: so is everything that acted for them.
70 let Some(person) = person else {
71 return Ok(None);
72 };
73 let agent = scope
74 .run
75 .as_ref()
76 .map(|run| run.agent.clone())
77 .unwrap_or_else(|| AGENT_NAME.to_owned());
78 // g1t's own run: the workspace's credential, acting as g1t, so the
79 // pull request and working copy g1t opened are its own (run.system).
80 let on_behalf_of = if scope.run.as_ref().is_some_and(|run| run.system) {
81 Principal {
82 id: g1t_contracts::system::ID.to_owned(),
83 username: g1t_contracts::system::USERNAME.to_owned(),
84 }
85 } else {
86 Principal {
87 id: person.id,
88 username: person.username,
89 }
90 };
91 Ok(Some(User {
92 id: AGENT_ID.to_owned(),
93 username: AGENT_NAME.to_owned(),
94 kind: PrincipalKind::Agent,
95 verified: person.verified,
96 workspaces: intersect(&person.workspaces, &scope.repo.namespace),
97 // The person's roles on the workspace's repositories, so an
98 // outside collaborator's agent works where they may, and never
99 // beyond Write (credentials::AGENT_CEILING).
100 grants: intersect_grants(&person.grants, &scope.repo.namespace),
101 acting: Some(Box::new(Acting {
102 credential_id: credential_id.to_owned(),
103 agent,
104 on_behalf_of,
105 scope,
106 })),
107 ..User::default()
108 }))
109 }
110
111 pub async fn create_run_credential(
112 &self,
113 a: CreateRunCredentialArgs,
114 ) -> Result<CreatedAccessToken> {
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.115 if !issued_for(a.kind, a.usage) {
Billing, integrations, security and identity no longer serve g1t's own agents. Billing stops metering agent runs, model tokens and AI Gateway requests, drops its model catalogue and price-keeper model prices, and stops selling AI credit, which only ever paid for those; credit bought earlier still pays toward what is owed. A usage report, statement or invoice that holds an old agent or model meter shows it as "Other usage" rather than failing, and the get_ai_credit and buy_ai_credit API operations and MCP billing actions go. Integrations no longer connects model providers or routes models, and no longer assigns imported issues or alerts to g1t; a model provider already connected can still be disconnected. Security drops "Fix with g1t". Identity no longer creates agent tokens or puts agents on teams, a team's lead is a person, and run credentials are issued only for checks, the merge queue, merge checks, deployments and bumps; tokens and credentials already issued keep working until they expire. The reserved names g1t and g1t-agent stay reserved. No tables are dropped.116 return Err(worker::Error::RustError(format!(
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.117 "no run credential is made for {} runs' {}",
118 a.kind.as_str(),
119 a.usage.as_str()
Billing, integrations, security and identity no longer serve g1t's own agents. Billing stops metering agent runs, model tokens and AI Gateway requests, drops its model catalogue and price-keeper model prices, and stops selling AI credit, which only ever paid for those; credit bought earlier still pays toward what is owed. A usage report, statement or invoice that holds an old agent or model meter shows it as "Other usage" rather than failing, and the get_ai_credit and buy_ai_credit API operations and MCP billing actions go. Integrations no longer connects model providers or routes models, and no longer assigns imported issues or alerts to g1t; a model provider already connected can still be disconnected. Security drops "Fix with g1t". Identity no longer creates agent tokens or puts agents on teams, a team's lead is a person, and run credentials are issued only for checks, the merge queue, merge checks, deployments and bumps; tokens and credentials already issued keep working until they expire. The reserved names g1t and g1t-agent stay reserved. No tables are dropped.120 )));
121 }
122 let agent = AGENT_NAME.to_owned();
README: run the core forge locally with Docker Compose; forks described as copies, not copy-on-write, until Cloudflare says otherwise123 let scope = AgentScope {
124 repo: a.repo.clone(),
125 operations: operations_for(a.kind, a.usage)
126 .into_iter()
127 .map(str::to_owned)
128 .collect(),
129 run: Some(RunBinding {
130 kind: a.kind,
131 usage: a.usage,
132 run_id: None,
133 number: a.number,
134 agent: agent.clone(),
135 system: a.on_behalf_of.kind == PrincipalKind::System,
136 read: a.read,
137 push: a.push,
138 }),
139 };
Billing, integrations, security and identity no longer serve g1t's own agents. Billing stops metering agent runs, model tokens and AI Gateway requests, drops its model catalogue and price-keeper model prices, and stops selling AI credit, which only ever paid for those; credit bought earlier still pays toward what is owed. A usage report, statement or invoice that holds an old agent or model meter shows it as "Other usage" rather than failing, and the get_ai_credit and buy_ai_credit API operations and MCP billing actions go. Integrations no longer connects model providers or routes models, and no longer assigns imported issues or alerts to g1t; a model provider already connected can still be disconnected. Security drops "Fix with g1t". Identity no longer creates agent tokens or puts agents on teams, a team's lead is a person, and run credentials are issued only for checks, the merge queue, merge checks, deployments and bumps; tokens and credentials already issued keep working until they expire. The reserved names g1t and g1t-agent stay reserved. No tables are dropped.140 // g1t's own work (a security update's bump) has no person behind it: its credential acts for the workspace,
README: run the core forge locally with Docker Compose; forks described as copies, not copy-on-write, until Cloudflare says otherwise141 // as a workspace's own token would.
142 let on_behalf_of = if a.on_behalf_of.kind == PrincipalKind::System {
143 match self.workspace_id_of(&a.repo.namespace).await? {
144 Some(id) => User {
145 id,
146 username: a.repo.namespace.to_lowercase(),
147 kind: PrincipalKind::Workspace,
148 ..User::default()
149 },
150 None => return Err(worker::Error::RustError(format!("no workspace {}", a.repo.namespace))),
151 }
152 } else {
153 a.on_behalf_of
154 };
155 let created = self
156 .create_access_token(CreateAccessTokenArgs {
157 user: on_behalf_of,
158 name: format!(
159 "{agent}: {} run in {}/{}{}",
160 a.kind.as_str(),
161 a.repo.namespace,
162 a.repo.name,
163 a.number.map(|n| format!("#{n}")).unwrap_or_default()
164 ),
165 ttl_seconds: Some(
166 a.ttl_seconds
167 .clamp(MIN_RUN_TTL_SECONDS, MAX_RUN_TTL_SECONDS),
168 ),
169 // A run credential's scope is its run's; see agent_scope.
170 scopes: None,
171 listed: false,
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.172 repo: None,
README: run the core forge locally with Docker Compose; forks described as copies, not copy-on-write, until Cloudflare says otherwise173 })
174 .await?;
175 self.db
176 .prepare("UPDATE access_tokens SET agent_scope = ? WHERE id = ?")
177 .bind(&[
178 serde_json::to_string(&scope)?.into(),
179 created.info.id.as_str().into(),
180 ])?
181 .run()
182 .await?;
183 Ok(created)
184 }
185
Billing, integrations, security and identity no longer serve g1t's own agents. Billing stops metering agent runs, model tokens and AI Gateway requests, drops its model catalogue and price-keeper model prices, and stops selling AI credit, which only ever paid for those; credit bought earlier still pays toward what is owed. A usage report, statement or invoice that holds an old agent or model meter shows it as "Other usage" rather than failing, and the get_ai_credit and buy_ai_credit API operations and MCP billing actions go. Integrations no longer connects model providers or routes models, and no longer assigns imported issues or alerts to g1t; a model provider already connected can still be disconnected. Security drops "Fix with g1t". Identity no longer creates agent tokens or puts agents on teams, a team's lead is a person, and run credentials are issued only for checks, the merge queue, merge checks, deployments and bumps; tokens and credentials already issued keep working until they expire. The reserved names g1t and g1t-agent stay reserved. No tables are dropped.186 /// Ties a sandbox's credentials to the run it recorded. A token
README: run the core forge locally with Docker Compose; forks described as copies, not copy-on-write, until Cloudflare says otherwise187 /// already bound keeps its run.
188 pub async fn bind_run_credentials(&self, a: BindRunCredentialsArgs) -> Result<bool> {
189 let hashes: Vec<&String> = a
190 .token_hashes
191 .iter()
192 .filter(|hash| is_hash(hash))
193 .take(MAX_HASHES)
194 .collect();
195 if hashes.is_empty() || a.run_id.trim().is_empty() {
196 return Ok(false);
197 }
198 let marks = vec!["?"; hashes.len()].join(", ");
199 let mut values: Vec<JsValue> = vec![a.run_id.as_str().into(), a.run_id.as_str().into()];
200 values.extend(hashes.iter().map(|hash| JsValue::from(hash.as_str())));
201 self.db
202 .prepare(format!(
203 "UPDATE access_tokens
204 SET run_id = ?, agent_scope = json_set(agent_scope, '$.run.runId', ?)
205 WHERE token_hash IN ({marks}) AND run_id IS NULL
206 AND json_extract(agent_scope, '$.run') IS NOT NULL"
207 ))
208 .bind(&values)?
209 .run()
210 .await?;
211 Ok(true)
212 }
213
214 /// Ends a sandbox's credentials: they stop working at once. Only run
215 /// credentials are touched.
216 pub async fn revoke_run_credentials(&self, a: RevokeRunCredentialsArgs) -> Result<bool> {
217 let hashes: Vec<&String> = a
218 .token_hashes
219 .iter()
220 .filter(|hash| is_hash(hash))
221 .take(MAX_HASHES)
222 .collect();
223 let mut conditions = Vec::new();
224 let mut values: Vec<JsValue> = Vec::new();
225 if !hashes.is_empty() {
226 conditions.push(format!(
227 "token_hash IN ({})",
228 vec!["?"; hashes.len()].join(", ")
229 ));
230 values.extend(hashes.iter().map(|hash| JsValue::from(hash.as_str())));
231 }
232 if let Some(run_id) = a.run_id.as_deref().filter(|id| !id.trim().is_empty()) {
233 conditions.push("run_id = ?".to_owned());
234 values.push(run_id.into());
235 }
236 if conditions.is_empty() {
237 return Ok(false);
238 }
239 self.db
240 .prepare(format!(
241 "UPDATE access_tokens SET expires_at = {SQL_NOW}
242 WHERE ({}) AND json_extract(agent_scope, '$.run') IS NOT NULL
243 AND (expires_at IS NULL OR expires_at > {SQL_NOW})",
244 conditions.join(" OR ")
245 ))
246 .bind(&values)?
247 .run()
248 .await?;
249 Ok(true)
250 }
251}
252
253#[cfg(test)]
254mod tests {
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.255 use super::{CredentialUse, RunCredentialKind, is_hash, issued_for};
Billing, integrations, security and identity no longer serve g1t's own agents. Billing stops metering agent runs, model tokens and AI Gateway requests, drops its model catalogue and price-keeper model prices, and stops selling AI credit, which only ever paid for those; credit bought earlier still pays toward what is owed. A usage report, statement or invoice that holds an old agent or model meter shows it as "Other usage" rather than failing, and the get_ai_credit and buy_ai_credit API operations and MCP billing actions go. Integrations no longer connects model providers or routes models, and no longer assigns imported issues or alerts to g1t; a model provider already connected can still be disconnected. Security drops "Fix with g1t". Identity no longer creates agent tokens or puts agents on teams, a team's lead is a person, and run credentials are issued only for checks, the merge queue, merge checks, deployments and bumps; tokens and credentials already issued keep working until they expire. The reserved names g1t and g1t-agent stay reserved. No tables are dropped.256
257 #[test]
258 fn credentials_are_made_only_for_sandbox_work_that_is_not_an_agents() {
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.259 let issued: Vec<&str> = RunCredentialKind::ALL
260 .iter()
261 .filter(|kind| issued_for(**kind, CredentialUse::Runner))
262 .map(|kind| kind.as_str())
263 .collect();
Billing, integrations, security and identity no longer serve g1t's own agents. Billing stops metering agent runs, model tokens and AI Gateway requests, drops its model catalogue and price-keeper model prices, and stops selling AI credit, which only ever paid for those; credit bought earlier still pays toward what is owed. A usage report, statement or invoice that holds an old agent or model meter shows it as "Other usage" rather than failing, and the get_ai_credit and buy_ai_credit API operations and MCP billing actions go. Integrations no longer connects model providers or routes models, and no longer assigns imported issues or alerts to g1t; a model provider already connected can still be disconnected. Security drops "Fix with g1t". Identity no longer creates agent tokens or puts agents on teams, a team's lead is a person, and run credentials are issued only for checks, the merge queue, merge checks, deployments and bumps; tokens and credentials already issued keep working until they expire. The reserved names g1t and g1t-agent stay reserved. No tables are dropped.264 assert_eq!(issued, ["checks", "queue", "mergecheck", "deploy", "bump"]);
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.265 // A retired hosted agent's tools token is never made.
266 assert!(RunCredentialKind::ALL.iter().all(|kind| !issued_for(*kind, CredentialUse::Tools)));
Billing, integrations, security and identity no longer serve g1t's own agents. Billing stops metering agent runs, model tokens and AI Gateway requests, drops its model catalogue and price-keeper model prices, and stops selling AI credit, which only ever paid for those; credit bought earlier still pays toward what is owed. A usage report, statement or invoice that holds an old agent or model meter shows it as "Other usage" rather than failing, and the get_ai_credit and buy_ai_credit API operations and MCP billing actions go. Integrations no longer connects model providers or routes models, and no longer assigns imported issues or alerts to g1t; a model provider already connected can still be disconnected. Security drops "Fix with g1t". Identity no longer creates agent tokens or puts agents on teams, a team's lead is a person, and run credentials are issued only for checks, the merge queue, merge checks, deployments and bumps; tokens and credentials already issued keep working until they expire. The reserved names g1t and g1t-agent stay reserved. No tables are dropped.267 }
README: run the core forge locally with Docker Compose; forks described as copies, not copy-on-write, until Cloudflare says otherwise268
269 #[test]
270 fn only_hashes_are_taken() {
271 assert!(is_hash(&"a1".repeat(32)));
272 assert!(!is_hash(&"A1".repeat(32)));
273 assert!(!is_hash("g1t_0123"));
274 assert!(!is_hash(&"0".repeat(63)));
275 }
276}

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