Skip to content
291 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.

Docs: the quickstart as steps, with both ways to put an agent on an issue1//! 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;
Merge account deletion: soft delete for 30 days, staff restore and purge, ghost for what remains (identity 0037)9pub mod account_deletion;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look10pub mod accounts;
Docs: the quickstart as steps, with both ways to put an agent on an issue11pub mod actions;
Agents and memory, checks and conflicts, profiles, slug renames, custom domains12pub mod agents;
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API13pub mod audit;
Merge branch 'worktree-agent-ac5b181a013e54348'14pub mod backups;
Docs: the quickstart as steps, with both ways to put an agent on an issue15pub mod billing;
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API16pub mod capture;
Merge checks: statuses and check runs on every commit17pub mod checks;
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar18pub mod codeowners;
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API19pub 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 yet20pub mod datasets;
Merge branch 'worktree-agent-a5a5de74d8863d554' into worktree-agent-a16631325aecf58ca21pub mod deploy_keys;
Docs: the quickstart as steps, with both ways to put an agent on an issue22pub 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 yet23pub mod folios;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look24pub mod github;
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API25pub mod guardrails;
Docs: the quickstart as steps, with both ways to put an agent on an issue26pub mod identity;
Inbox: the events service tells people what needs them as events arrive27pub mod inbox;
Docs: the quickstart as steps, with both ways to put an agent on an issue28pub mod integrations;
Merge main (membership, two-factor, GitHub repo roles) into tokens29pub mod members;
Merge branch 'mirroring' into artifacts-mode30pub mod mirrors;
Docs: the quickstart as steps, with both ways to put an agent on an issue31mod ids;
32mod names;
33mod outcome;
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member34pub 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.35pub mod people;
Projects: what a workspace builds and runs, first on every page36pub mod projects;
Docs: the quickstart as steps, with both ways to put an agent on an issue37pub mod repos;
Merge rulesets: branch and tag rules, agent-first, enforced on push and merge38pub mod rules;
Fast pages, required checks on the branch, self-hosted runners, honest incidents39pub mod runners;
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step40pub mod scopes;
Search across all of g1t, Explore, and a command palette41pub mod search;
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API42pub mod security;
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar43pub mod teams;
44pub mod security_suite;
Merge branch 'worktree-agent-ad8a36dfcd4176015' into spend-guardrails45pub mod subscribers;
Docs: the quickstart as steps, with both ways to put an agent on an issue46pub mod time;
Fine-grained personal tokens, workspace token rules and approvals in identity47pub mod tokens;
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar48pub mod updates;
Docs: the quickstart as steps, with both ways to put an agent on an issue49pub mod webhooks;
50pub mod work;
51
52pub use ids::new_id;
Merge branch 'worktree-agent-a8385d293d42c913a'53pub use names::{
One kind of access token; presence and status; usernames keep their case; the tour is a miniature of the real app; icons for password managers54 Username, aliasable_name, claimable_namespace, claimable_username, is_namespace_shaped, is_reserved_name, is_route_name,
55 is_valid_namespace, is_valid_repo_name,
Merge branch 'worktree-agent-a8385d293d42c913a'56};
Docs: the quickstart as steps, with both ways to put an agent on an issue57pub use outcome::{Failure, FailureCode, Outcome};
58
59use serde::{Deserialize, Serialize};
60
Merge main (membership, two-factor, GitHub repo roles) into tokens61/// What a member may do in a workspace. A member may also hold
62/// [`members::OrgRole`]s, which add to it.
Docs: the quickstart as steps, with both ways to put an agent on an issue63#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
64#[serde(rename_all = "lowercase")]
65pub enum Role {
Merge main (membership, two-factor, GitHub repo roles) into tokens66 /// Everything: Admin on every repository, the workspace's members,
67 /// settings, billing and security.
Docs: the quickstart as steps, with both ways to put an agent on an issue68 Owner,
Merge main (membership, two-factor, GitHub repo roles) into tokens69 /// The workspace's base permission on each repository, and what its
70 /// member privileges allow (see [`members::MemberPrivileges`]).
Docs: the quickstart as steps, with both ways to put an agent on an issue71 Member,
72}
73
Merge main (membership, two-factor, GitHub repo roles) into tokens74pub use members::{MemberPrivileges, OrgRole};
75
Docs: the quickstart as steps, with both ways to put an agent on an issue76/// One workspace a user belongs to.
77#[derive(Clone, Debug, Serialize, Deserialize)]
78pub struct Membership {
79 /// The workspace's name in URLs: `g1t.sh/<slug>`.
80 pub slug: String,
81 pub role: Role,
Workspace names and icons, and a component kit for every control82 /// The workspace's display name, for showing it to people. Set when a
83 /// user is resolved from credentials; absent on principals made up by
84 /// a service.
85 #[serde(default, skip_serializing_if = "Option::is_none")]
86 pub name: Option<String>,
87 /// The workspace's uploaded icon: the SHA-256 of its bytes, served at
88 /// `/avatars/<avatar>`. Absent means the generated letter avatar.
89 #[serde(default, skip_serializing_if = "Option::is_none")]
90 pub avatar: Option<String>,
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look91 /// What a member gets on each of the workspace's repositories: the
92 /// workspace's base permission. Set when a user is resolved from
93 /// credentials; absent means the default, Write. Owners have Admin
94 /// whatever it says. See [`access`].
95 #[serde(default, skip_serializing_if = "Option::is_none")]
96 pub base_permission: Option<access::BasePermission>,
Merge branch 'worktree-agent-ad7c6d88d93adc817'97 /// Who may create the workspace's teams. Set when a user is resolved
98 /// from credentials; absent means the default, any member. See
99 /// [`teams::TeamCreation`].
100 #[serde(default, skip_serializing_if = "Option::is_none")]
101 pub team_creation: Option<teams::TeamCreation>,
Merge main (membership, two-factor, GitHub repo roles) into tokens102 /// The roles the member holds besides `role`: billing manager,
103 /// security manager. Set when a user is resolved from credentials.
104 #[serde(default, skip_serializing_if = "Vec::is_empty")]
105 pub org_roles: Vec<OrgRole>,
106 /// What the workspace lets members (and repository admins) do. Set
107 /// when a user is resolved from credentials; absent means the
108 /// defaults. See [`members::MemberPrivileges`].
109 #[serde(default, skip_serializing_if = "Option::is_none")]
110 pub privileges: Option<MemberPrivileges>,
Docs: the quickstart as steps, with both ways to put an agent on an issue111}
112
Workspace names and icons, and a component kit for every control113impl Membership {
114 /// A plain member of `slug`, as services act inside one workspace.
115 pub fn member(slug: impl Into<String>) -> Self {
116 Membership {
117 slug: slug.into(),
118 role: Role::Member,
119 name: None,
120 avatar: None,
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look121 base_permission: None,
Merge branch 'worktree-agent-ad7c6d88d93adc817'122 team_creation: None,
Merge main (membership, two-factor, GitHub repo roles) into tokens123 org_roles: Vec::new(),
124 privileges: None,
Workspace names and icons, and a component kit for every control125 }
126 }
Merge main (membership, two-factor, GitHub repo roles) into tokens127
128 /// Whether the member holds `role` besides owner or member.
129 pub fn has(&self, role: OrgRole) -> bool {
130 self.org_roles.contains(&role)
131 }
Workspace names and icons, and a component kit for every control132}
133
Docs: the quickstart as steps, with both ways to put an agent on an issue134/// What a set of credentials resolved to.
135#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
136#[serde(rename_all = "lowercase")]
137pub enum PrincipalKind {
138 /// A person's account.
139 #[default]
140 User,
141 /// A workspace, acting through one of its own access tokens. Its `id`
142 /// is the workspace's, its `username` the workspace's slug, and it is a
143 /// member of that workspace and no other.
144 Workspace,
145 /// A g1t agent at work in a sandbox, acting through a token that lives
146 /// 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-agent147 /// one repository. Its `username` is `g1t`.
Docs: the quickstart as steps, with both ways to put an agent on an issue148 Agent,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily149 /// g1t itself: the platform acting on its own, as when it opens a
150 /// pull request to upgrade a vulnerable dependency or merges from the
151 /// queue. Never resolved from credentials: only services make one,
152 /// with [`User::system`]. Its `username` is `g1t`, which nobody can
153 /// register.
154 System,
155}
156
157/// g1t's own identity, as [`PrincipalKind::System`] work is recorded.
158pub mod system {
159 /// Its id wherever an author or actor id is stored.
160 pub const ID: &str = "g1t";
161 /// Its name, shown as the author of what it does.
162 pub const USERNAME: &str = "g1t";
163 /// The address on the commits it makes, which no mailbox receives.
164 pub const EMAIL: &str = "g1t@users.noreply.g1t.sh";
165 /// Ids that earlier versions stored for g1t's own actions, such as a
166 /// merge its settings made. Read as g1t too.
167 pub const LEGACY_IDS: [&str; 3] = ["g1t_policy", "svc_runner", "g1t_runner"];
168
169 /// Whether `id` is g1t's own.
170 pub fn is_system_id(id: &str) -> bool {
171 id == ID || LEGACY_IDS.contains(&id)
172 }
Docs: the quickstart as steps, with both ways to put an agent on an issue173}
174
175#[derive(Clone, Debug, Default, Serialize, Deserialize)]
176pub struct User {
177 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 managers178 /// Lowercased: what the person is found, linked and mentioned by.
Docs: the quickstart as steps, with both ways to put an agent on an issue179 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 managers180 /// The username as its owner wrote it (`Ana`), when that differs from
181 /// `username`: what pages show. Set on the signed-in person and on
182 /// people looked up by name; absent elsewhere, where `username` is shown.
183 #[serde(default, skip_serializing_if = "Option::is_none")]
184 pub display_username: Option<String>,
Docs: the quickstart as steps, with both ways to put an agent on an issue185 #[serde(default)]
186 pub kind: PrincipalKind,
187 /// Whether the account's email address has been confirmed. Unverified
188 /// accounts can sign in but cannot create or change anything.
189 #[serde(default)]
190 pub verified: bool,
191 /// The workspaces this user belongs to. Filled in when a user is
192 /// resolved from credentials, so any service can authorize from it.
193 #[serde(default)]
194 pub workspaces: Vec<Membership>,
Workspace names and icons, and a component kit for every control195 /// The person's uploaded avatar: the SHA-256 of its bytes, served at
196 /// `/avatars/<avatar>`. Absent means the generated letter avatar.
197 #[serde(default, skip_serializing_if = "Option::is_none")]
198 pub avatar: Option<String>,
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API199 /// Set on an agent resolved from its token: who it acts for, with which
200 /// credential, and what it may do. See [`credentials`].
201 #[serde(default, skip_serializing_if = "Option::is_none")]
202 pub acting: Option<Box<credentials::Acting>>,
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look203 /// The repositories this user has been given a role on directly,
204 /// whether or not they belong to its workspace. Filled in with
205 /// `workspaces`; see [`access`].
206 #[serde(default, skip_serializing_if = "Vec::is_empty")]
207 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 step208 /// Set on a user resolved from an access token: its scopes and the
209 /// workspaces or repositories it is limited to. Absent on a signed-in
210 /// session and on an agent (whose `acting` scope applies instead).
211 /// See [`scopes`].
212 #[serde(default, skip_serializing_if = "Option::is_none")]
213 pub token: Option<Box<scopes::TokenAccess>>,
Merge main (membership, two-factor, GitHub repo roles) into tokens214 /// The workspaces this person belongs to but cannot use until they
215 /// meet its policy, such as turning on two-factor authentication.
216 /// They are left out of `workspaces` and `grants` meanwhile. Set when
217 /// a person is resolved from a session.
218 #[serde(default, skip_serializing_if = "Vec::is_empty")]
219 pub held: Vec<members::PolicyHold>,
Docs: the quickstart as steps, with both ways to put an agent on an issue220}
221
222impl User {
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily223 /// g1t itself, acting in `workspace`: what the platform's own work,
224 /// such as security updates, is done and recorded as.
225 pub fn system(workspace: &str) -> User {
226 User {
227 id: system::ID.to_owned(),
228 username: system::USERNAME.to_owned(),
229 kind: PrincipalKind::System,
230 verified: true,
231 workspaces: vec![Membership::member(workspace.to_lowercase())],
232 ..User::default()
233 }
234 }
235
236 /// Whether this is g1t itself.
237 pub fn is_system(&self) -> bool {
238 self.kind == PrincipalKind::System
239 }
240
Merge email confirmation gate: a code and a link, nothing until confirmed (identity 0036)241 /// Whether this is a person whose account has not confirmed its email
242 /// address. Such an account can only confirm it (or change it, or sign
243 /// out): the site, the API, MCP and git refuse it everything else
244 /// ([`accounts::confirm_email_first`]).
245 pub fn awaits_confirmation(&self) -> bool {
246 self.kind == PrincipalKind::User && !self.verified
247 }
248
Docs: the quickstart as steps, with both ways to put an agent on an issue249 pub fn role_in(&self, slug: &str) -> Option<Role> {
250 self.workspaces
251 .iter()
252 .find(|membership| membership.slug == slug)
253 .map(|membership| membership.role)
254 }
255
256 pub fn is_member(&self, slug: &str) -> bool {
257 self.role_in(slug).is_some()
258 }
Merge main (membership, two-factor, GitHub repo roles) into tokens259
260 /// The membership in `slug`, if any.
261 pub fn membership(&self, slug: &str) -> Option<&Membership> {
262 self.workspaces.iter().find(|membership| membership.slug.eq_ignore_ascii_case(slug))
263 }
264
265 /// Whether this is a person who owns `slug`, or holds `role` in it.
266 pub fn owns_or_has(&self, slug: &str, role: OrgRole) -> bool {
267 self.membership(slug)
268 .is_some_and(|membership| membership.role == Role::Owner || membership.has(role))
269 }
270
271 /// Whether the user may manage `slug`'s billing: an owner or a billing
272 /// manager.
273 pub fn manages_billing(&self, slug: &str) -> bool {
274 self.owns_or_has(slug, OrgRole::BillingManager)
275 }
276
277 /// Whether the user may see and manage security across `slug`: an
278 /// owner or a security manager.
279 pub fn manages_security(&self, slug: &str) -> bool {
280 self.owns_or_has(slug, OrgRole::SecurityManager)
281 }
282
283 /// The workspace's member privileges as this user sees them: the
284 /// defaults when the membership does not say.
285 pub fn privileges_in(&self, slug: &str) -> MemberPrivileges {
286 self.membership(slug).and_then(|membership| membership.privileges).unwrap_or_default()
287 }
Docs: the quickstart as steps, with both ways to put an agent on an issue288}
289
290/// Who is asking. Every read and write in every service takes one.
291pub type Viewer = Option<User>;

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