Skip to content
293 linesCodeBlameRaw

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

The statement is a month at a time, a line per kind of charge1//! Types and service interfaces shared by every g1t service.
2//!
3//! Each service has a module here holding the data it exchanges and the
4//! arguments of each of its methods. Services and their callers depend on
5//! this crate, never on each other's code.
6
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb977pub mod about;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look8pub mod access;
Security tells people the way they can live with. Each scan publishes one summary event per alert type (secret_scanning_alert.summary, code_scanning_alert.summary, vulnerability_alert.summary: what it opened, by severity, what it fixed, what is open now, the worst new alert and the newest one's title, with the owners and security managers to tell) beside the per-alert events webhooks keep, so the inbox holds one thread per repository and alert type that the next scan brings up to date instead of one item per finding, and the ids are capped at 200 while the counts are not. Critical and high alerts and a refused push reach the inbox at once (and toast like a mention, as the new security notification kind); medium and low wait for each person's security digest, one inbox item and email per workspace, daily or weekly as they choose in their notification settings, at once, or never; a scan that opened nothing refreshes the thread quietly ("2 of 3 fixed") and marks it done when nothing is left open; and security alerts are emailed by default. A repository can turn alerts for secrets found in its history off while push protection stays on. Reporting arrives: security advisories (G1TSA ids, drafts published and withdrawn by Admins and security managers, visible to anyone who can see the repository once published) and private vulnerability reporting (a repository setting; anyone who can see it may report, signed out with an email on a public one, five a day each, and the owners and security managers are told at once), each with its RPC methods, REST routes under /repos/{owner}/{name}/security/advisories and /security/reports, MCP actions, scopes and reference examples.9pub mod advisories;
Merge account deletion: soft delete for 30 days, staff restore and purge, ghost for what remains (identity 0037)10pub mod account_deletion;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look11pub mod accounts;
The statement is a month at a time, a line per kind of charge12pub mod actions;
13pub mod agents;
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API14pub mod audit;
Merge branch 'worktree-agent-ac5b181a013e54348'15pub mod backups;
The statement is a month at a time, a line per kind of charge16pub mod billing;
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API17pub mod capture;
Merge checks: statuses and check runs on every commit18pub mod checks;
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar19pub mod codeowners;
Coding agents show as themselves on commits and contributors: Claude, Codex, Copilot, Gemini, Jules, Cursor, Devin, Aider, Dependabot, Renovate and GitHub Actions are known by the address they write on their commits (never by name), shown with their maker's mark, their own name and an agent or bot label, and a card saying what each is. Anyone else not on g1t gets a card too, saying so and how to claim the commits by adding the address. Contributor lists are worked out again (stats version 2) so an agent counts once.20pub mod coding_agents;
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API21pub mod credentials;
Artifacts contracts: folios, their four kinds, dashboard datasets, folio events and the artifacts scopes are typed and validated the same in TypeScript and Rust, with nothing using them yet22pub mod datasets;
Merge branch 'worktree-agent-a5a5de74d8863d554' into worktree-agent-a16631325aecf58ca23pub mod deploy_keys;
The statement is a month at a time, a line per kind of charge24pub mod events;
Artifacts contracts: folios, their four kinds, dashboard datasets, folio events and the artifacts scopes are typed and validated the same in TypeScript and Rust, with nothing using them yet25pub mod folios;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look26pub mod github;
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API27pub mod guardrails;
The statement is a month at a time, a line per kind of charge28pub mod identity;
Inbox: the events service tells people what needs them as events arrive29pub mod inbox;
The statement is a month at a time, a line per kind of charge30pub mod integrations;
Merge main (membership, two-factor, GitHub repo roles) into tokens31pub mod members;
Merge branch 'mirroring' into artifacts-mode32pub mod mirrors;
The statement is a month at a time, a line per kind of charge33mod ids;
34mod names;
35mod outcome;
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member36pub mod packages;
People and teams are front and centre: one directory of people and agents with presence, local time, titles, teams and what each owns; profiles with manager and reports and the agents they work with; an org chart with each team's agents beside the person who leads it; and teams of any mix, with a lead, a channel, a budget agents keep to and the agents on them. Every agent is told its teams each turn (who leads, who owns what, who's around and who to page), and the team page shows exactly what. Member management is Members and invites; the people and teams guide says how.37pub mod people;
The statement is a month at a time, a line per kind of charge38pub mod projects;
39pub mod repos;
Merge rulesets: branch and tag rules, agent-first, enforced on push and merge40pub mod rules;
Fast pages, required checks on the branch, self-hosted runners, honest incidents41pub mod runners;
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step42pub mod scopes;
Search across all of g1t, Explore, and a command palette43pub mod search;
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API44pub mod security;
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar45pub mod teams;
46pub mod security_suite;
Merge branch 'worktree-agent-ad8a36dfcd4176015' into spend-guardrails47pub mod subscribers;
The statement is a month at a time, a line per kind of charge48pub mod time;
Fine-grained personal tokens, workspace token rules and approvals in identity49pub mod tokens;
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar50pub mod updates;
The statement is a month at a time, a line per kind of charge51pub mod webhooks;
52pub mod work;
53
Home says what people did as well as what agents did. Since you were last here now has a People column and an Agents column: who pushed how many commits to which projects, pull requests opened, merged and reviewed, issues opened and closed, docs edited, messages sent and deploys that went out, each line a link to where those are listed, with the agents' acceptance (first time, after review, didn't finish) kept as a row of their column; the sentence under the heading sums it up honestly, and says when a part of g1t could not be read, or that the span was quiet. Landed counts merged pull requests, commits pushed straight to a default branch, production deploys that went live, releases and packages, newest first; Running now adds workflow runs. Behind it, the events service answers an activity digest over a span in one round trip from its existing indexes, every push now records how many commits it carried, and chat counts the messages sent in the conversations you can read. The Home guide defines every line, and says how this scales.54pub use ids::{id_floor, new_id};
Merge branch 'worktree-agent-a8385d293d42c913a'55pub use names::{
Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9'56 Username, aliasable_name, claimable_namespace, is_action_owner_name, is_claimable_name, claimable_username, is_namespace_shaped, is_reserved_name, is_route_name,
One kind of access token; presence and status; usernames keep their case; the tour is a miniature of the real app; icons for password managers57 is_valid_namespace, is_valid_repo_name,
Merge branch 'worktree-agent-a8385d293d42c913a'58};
The statement is a month at a time, a line per kind of charge59pub use outcome::{Failure, FailureCode, Outcome};
60
61use serde::{Deserialize, Serialize};
62
Merge main (membership, two-factor, GitHub repo roles) into tokens63/// What a member may do in a workspace. A member may also hold
64/// [`members::OrgRole`]s, which add to it.
The statement is a month at a time, a line per kind of charge65#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
66#[serde(rename_all = "lowercase")]
67pub enum Role {
Merge main (membership, two-factor, GitHub repo roles) into tokens68 /// Everything: Admin on every repository, the workspace's members,
69 /// settings, billing and security.
The statement is a month at a time, a line per kind of charge70 Owner,
Merge main (membership, two-factor, GitHub repo roles) into tokens71 /// The workspace's base permission on each repository, and what its
72 /// member privileges allow (see [`members::MemberPrivileges`]).
The statement is a month at a time, a line per kind of charge73 Member,
74}
75
Merge main (membership, two-factor, GitHub repo roles) into tokens76pub use members::{MemberPrivileges, OrgRole};
77
The statement is a month at a time, a line per kind of charge78/// One workspace a user belongs to.
79#[derive(Clone, Debug, Serialize, Deserialize)]
80pub struct Membership {
81 /// The workspace's name in URLs: `g1t.sh/<slug>`.
82 pub slug: String,
83 pub role: Role,
84 /// The workspace's display name, for showing it to people. Set when a
85 /// user is resolved from credentials; absent on principals made up by
86 /// a service.
87 #[serde(default, skip_serializing_if = "Option::is_none")]
88 pub name: Option<String>,
89 /// The workspace's uploaded icon: the SHA-256 of its bytes, served at
90 /// `/avatars/<avatar>`. Absent means the generated letter avatar.
91 #[serde(default, skip_serializing_if = "Option::is_none")]
92 pub avatar: Option<String>,
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look93 /// What a member gets on each of the workspace's repositories: the
94 /// workspace's base permission. Set when a user is resolved from
95 /// credentials; absent means the default, Write. Owners have Admin
96 /// whatever it says. See [`access`].
97 #[serde(default, skip_serializing_if = "Option::is_none")]
98 pub base_permission: Option<access::BasePermission>,
Merge branch 'worktree-agent-ad7c6d88d93adc817'99 /// Who may create the workspace's teams. Set when a user is resolved
100 /// from credentials; absent means the default, any member. See
101 /// [`teams::TeamCreation`].
102 #[serde(default, skip_serializing_if = "Option::is_none")]
103 pub team_creation: Option<teams::TeamCreation>,
Merge main (membership, two-factor, GitHub repo roles) into tokens104 /// The roles the member holds besides `role`: billing manager,
105 /// security manager. Set when a user is resolved from credentials.
106 #[serde(default, skip_serializing_if = "Vec::is_empty")]
107 pub org_roles: Vec<OrgRole>,
108 /// What the workspace lets members (and repository admins) do. Set
109 /// when a user is resolved from credentials; absent means the
110 /// defaults. See [`members::MemberPrivileges`].
111 #[serde(default, skip_serializing_if = "Option::is_none")]
112 pub privileges: Option<MemberPrivileges>,
The statement is a month at a time, a line per kind of charge113}
114
115impl Membership {
116 /// A plain member of `slug`, as services act inside one workspace.
117 pub fn member(slug: impl Into<String>) -> Self {
118 Membership {
119 slug: slug.into(),
120 role: Role::Member,
121 name: None,
122 avatar: None,
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look123 base_permission: None,
Merge branch 'worktree-agent-ad7c6d88d93adc817'124 team_creation: None,
Merge main (membership, two-factor, GitHub repo roles) into tokens125 org_roles: Vec::new(),
126 privileges: None,
The statement is a month at a time, a line per kind of charge127 }
128 }
Merge main (membership, two-factor, GitHub repo roles) into tokens129
130 /// Whether the member holds `role` besides owner or member.
131 pub fn has(&self, role: OrgRole) -> bool {
132 self.org_roles.contains(&role)
133 }
The statement is a month at a time, a line per kind of charge134}
135
136/// What a set of credentials resolved to.
137#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
138#[serde(rename_all = "lowercase")]
139pub enum PrincipalKind {
140 /// A person's account.
141 #[default]
142 User,
143 /// A workspace, acting through one of its own access tokens. Its `id`
144 /// is the workspace's, its `username` the workspace's slug, and it is a
145 /// member of that workspace and no other.
146 Workspace,
147 /// A g1t agent at work in a sandbox, acting through a token that lives
148 /// as long as its run and can do only what that token's scope lists, in
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent149 /// one repository. Its `username` is `g1t`.
The statement is a month at a time, a line per kind of charge150 Agent,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily151 /// g1t itself: the platform acting on its own, as when it opens a
152 /// pull request to upgrade a vulnerable dependency or merges from the
153 /// queue. Never resolved from credentials: only services make one,
154 /// with [`User::system`]. Its `username` is `g1t`, which nobody can
155 /// register.
156 System,
157}
158
159/// g1t's own identity, as [`PrincipalKind::System`] work is recorded.
160pub mod system {
161 /// Its id wherever an author or actor id is stored.
162 pub const ID: &str = "g1t";
163 /// Its name, shown as the author of what it does.
164 pub const USERNAME: &str = "g1t";
165 /// The address on the commits it makes, which no mailbox receives.
166 pub const EMAIL: &str = "g1t@users.noreply.g1t.sh";
167 /// Ids that earlier versions stored for g1t's own actions, such as a
168 /// merge its settings made. Read as g1t too.
169 pub const LEGACY_IDS: [&str; 3] = ["g1t_policy", "svc_runner", "g1t_runner"];
170
171 /// Whether `id` is g1t's own.
172 pub fn is_system_id(id: &str) -> bool {
173 id == ID || LEGACY_IDS.contains(&id)
174 }
The statement is a month at a time, a line per kind of charge175}
176
177#[derive(Clone, Debug, Default, Serialize, Deserialize)]
178pub struct User {
179 pub id: String,
One kind of access token; presence and status; usernames keep their case; the tour is a miniature of the real app; icons for password managers180 /// Lowercased: what the person is found, linked and mentioned by.
The statement is a month at a time, a line per kind of charge181 pub username: String,
One kind of access token; presence and status; usernames keep their case; the tour is a miniature of the real app; icons for password managers182 /// The username as its owner wrote it (`Ana`), when that differs from
183 /// `username`: what pages show. Set on the signed-in person and on
184 /// people looked up by name; absent elsewhere, where `username` is shown.
185 #[serde(default, skip_serializing_if = "Option::is_none")]
186 pub display_username: Option<String>,
The statement is a month at a time, a line per kind of charge187 #[serde(default)]
188 pub kind: PrincipalKind,
189 /// Whether the account's email address has been confirmed. Unverified
190 /// accounts can sign in but cannot create or change anything.
191 #[serde(default)]
192 pub verified: bool,
193 /// The workspaces this user belongs to. Filled in when a user is
194 /// resolved from credentials, so any service can authorize from it.
195 #[serde(default)]
196 pub workspaces: Vec<Membership>,
197 /// The person's uploaded avatar: the SHA-256 of its bytes, served at
198 /// `/avatars/<avatar>`. Absent means the generated letter avatar.
199 #[serde(default, skip_serializing_if = "Option::is_none")]
200 pub avatar: Option<String>,
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API201 /// Set on an agent resolved from its token: who it acts for, with which
202 /// credential, and what it may do. See [`credentials`].
203 #[serde(default, skip_serializing_if = "Option::is_none")]
204 pub acting: Option<Box<credentials::Acting>>,
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look205 /// The repositories this user has been given a role on directly,
206 /// whether or not they belong to its workspace. Filled in with
207 /// `workspaces`; see [`access`].
208 #[serde(default, skip_serializing_if = "Vec::is_empty")]
209 pub grants: Vec<access::RepoGrant>,
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step210 /// Set on a user resolved from an access token: its scopes and the
211 /// workspaces or repositories it is limited to. Absent on a signed-in
212 /// session and on an agent (whose `acting` scope applies instead).
213 /// See [`scopes`].
214 #[serde(default, skip_serializing_if = "Option::is_none")]
215 pub token: Option<Box<scopes::TokenAccess>>,
Merge main (membership, two-factor, GitHub repo roles) into tokens216 /// The workspaces this person belongs to but cannot use until they
217 /// meet its policy, such as turning on two-factor authentication.
218 /// They are left out of `workspaces` and `grants` meanwhile. Set when
219 /// a person is resolved from a session.
220 #[serde(default, skip_serializing_if = "Vec::is_empty")]
221 pub held: Vec<members::PolicyHold>,
The statement is a month at a time, a line per kind of charge222}
223
224impl User {
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily225 /// g1t itself, acting in `workspace`: what the platform's own work,
226 /// such as security updates, is done and recorded as.
227 pub fn system(workspace: &str) -> User {
228 User {
229 id: system::ID.to_owned(),
230 username: system::USERNAME.to_owned(),
231 kind: PrincipalKind::System,
232 verified: true,
233 workspaces: vec![Membership::member(workspace.to_lowercase())],
234 ..User::default()
235 }
236 }
237
238 /// Whether this is g1t itself.
239 pub fn is_system(&self) -> bool {
240 self.kind == PrincipalKind::System
241 }
242
Merge email confirmation gate: a code and a link, nothing until confirmed (identity 0036)243 /// Whether this is a person whose account has not confirmed its email
244 /// address. Such an account can only confirm it (or change it, or sign
245 /// out): the site, the API, MCP and git refuse it everything else
246 /// ([`accounts::confirm_email_first`]).
247 pub fn awaits_confirmation(&self) -> bool {
248 self.kind == PrincipalKind::User && !self.verified
249 }
250
The statement is a month at a time, a line per kind of charge251 pub fn role_in(&self, slug: &str) -> Option<Role> {
252 self.workspaces
253 .iter()
254 .find(|membership| membership.slug == slug)
255 .map(|membership| membership.role)
256 }
257
258 pub fn is_member(&self, slug: &str) -> bool {
259 self.role_in(slug).is_some()
260 }
Merge main (membership, two-factor, GitHub repo roles) into tokens261
262 /// The membership in `slug`, if any.
263 pub fn membership(&self, slug: &str) -> Option<&Membership> {
264 self.workspaces.iter().find(|membership| membership.slug.eq_ignore_ascii_case(slug))
265 }
266
267 /// Whether this is a person who owns `slug`, or holds `role` in it.
268 pub fn owns_or_has(&self, slug: &str, role: OrgRole) -> bool {
269 self.membership(slug)
270 .is_some_and(|membership| membership.role == Role::Owner || membership.has(role))
271 }
272
273 /// Whether the user may manage `slug`'s billing: an owner or a billing
274 /// manager.
275 pub fn manages_billing(&self, slug: &str) -> bool {
276 self.owns_or_has(slug, OrgRole::BillingManager)
277 }
278
279 /// Whether the user may see and manage security across `slug`: an
280 /// owner or a security manager.
281 pub fn manages_security(&self, slug: &str) -> bool {
282 self.owns_or_has(slug, OrgRole::SecurityManager)
283 }
284
285 /// The workspace's member privileges as this user sees them: the
286 /// defaults when the membership does not say.
287 pub fn privileges_in(&self, slug: &str) -> MemberPrivileges {
288 self.membership(slug).and_then(|membership| membership.privileges).unwrap_or_default()
289 }
The statement is a month at a time, a line per kind of charge290}
291
292/// Who is asking. Every read and write in every service takes one.
293pub type Viewer = Option<User>;

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