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
295 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.

Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them1//! 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;
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them8pub mod access;
Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r99pub mod advisories;
Merge account deletion: soft delete for 30 days, staff restore and purge, ghost for what remains (identity 0037)10pub mod account_deletion;
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them11pub mod accounts;
12pub mod actions;
13pub mod agents;
14pub mod audit;
Merge branch 'worktree-agent-ac5b181a013e54348'15pub mod backups;
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them16pub mod billing;
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;
Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r919pub mod coding_agents;
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them20pub 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 yet21pub mod datasets;
Merge branch 'worktree-agent-a5a5de74d8863d554' into worktree-agent-a16631325aecf58ca22pub mod deploy_keys;
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them23pub 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 yet24pub mod folios;
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them25pub mod github;
26pub mod guardrails;
27pub mod identity;
Inbox: the events service tells people what needs them as events arrive28pub mod inbox;
Merge branch 'worktree-agent-a5c94df323642630e'29pub mod live;
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them30pub mod integrations;
Merge main (membership, two-factor, GitHub repo roles) into tokens31pub mod members;
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them32mod ids;
33mod names;
34mod outcome;
35pub 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.36pub mod people;
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them37pub mod projects;
38pub mod repos;
Merge rulesets: branch and tag rules, agent-first, enforced on push and merge39pub mod rules;
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them40pub mod runners;
41pub mod scopes;
42pub mod search;
43pub mod security;
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar44pub mod teams;
45pub mod security_suite;
Merge branch 'worktree-agent-ad8a36dfcd4176015' into spend-guardrails46pub mod subscribers;
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them47pub mod time;
Fine-grained personal tokens, workspace token rules and approvals in identity48pub mod tokens;
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar49pub mod updates;
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them50pub mod webhooks;
51pub mod work;
52
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.53pub use ids::{id_floor, new_id};
Merge branch 'worktree-agent-a8385d293d42c913a'54pub use names::{
A workflow's `uses: actions/setup-node@v4` means GitHub's `actions` again, whoever is on g1t. g1t looked for a repository on g1t before GitHub, and anyone could make a public workspace called `actions`, `docker` or `aws-actions` and have its `setup-node` run in every workflow that names GitHub's, with that job's secrets. Now another workspace's public repository answers only for a name GitHub has no public repository of; the caller's own workspace and g1t's own `g1t/…` still answer from g1t, and when GitHub can't be asked, GitHub's is used. The names of the GitHub accounts whose actions workflows use most can no longer be registered, renamed to, or taken by signing up with GitHub (which suggests the name with `-gh`); an account that has one keeps it, and mentions and invitations still find it. The Actions, authentication and workspaces guides say so.55 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 managers56 is_valid_namespace, is_valid_repo_name,
Merge branch 'worktree-agent-a8385d293d42c913a'57};
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them58pub use outcome::{Failure, FailureCode, Outcome};
59
60use serde::{Deserialize, Serialize};
61
Merge main (membership, two-factor, GitHub repo roles) into tokens62/// What a member may do in a workspace. A member may also hold
63/// [`members::OrgRole`]s, which add to it.
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them64#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
65#[serde(rename_all = "lowercase")]
66pub enum Role {
Merge main (membership, two-factor, GitHub repo roles) into tokens67 /// Everything: Admin on every repository, the workspace's members,
68 /// settings, billing and security.
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them69 Owner,
Merge main (membership, two-factor, GitHub repo roles) into tokens70 /// The workspace's base permission on each repository, and what its
71 /// member privileges allow (see [`members::MemberPrivileges`]).
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them72 Member,
73}
74
Merge main (membership, two-factor, GitHub repo roles) into tokens75pub use members::{MemberPrivileges, OrgRole};
76
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them77/// One workspace a user belongs to.
78#[derive(Clone, Debug, Serialize, Deserialize)]
79pub struct Membership {
80 /// The workspace's name in URLs: `g1t.sh/<slug>`.
81 pub slug: String,
82 pub role: Role,
83 /// The workspace's display name, for showing it to people. Set when a
84 /// user is resolved from credentials; absent on principals made up by
85 /// a service.
86 #[serde(default, skip_serializing_if = "Option::is_none")]
87 pub name: Option<String>,
88 /// The workspace's uploaded icon: the SHA-256 of its bytes, served at
89 /// `/avatars/<avatar>`. Absent means the generated letter avatar.
90 #[serde(default, skip_serializing_if = "Option::is_none")]
91 pub avatar: Option<String>,
92 /// What a member gets on each of the workspace's repositories: the
93 /// workspace's base permission. Set when a user is resolved from
94 /// credentials; absent means the default, Write. Owners have Admin
95 /// whatever it says. See [`access`].
96 #[serde(default, skip_serializing_if = "Option::is_none")]
97 pub base_permission: Option<access::BasePermission>,
Merge branch 'worktree-agent-ad7c6d88d93adc817'98 /// Who may create the workspace's teams. Set when a user is resolved
99 /// from credentials; absent means the default, any member. See
100 /// [`teams::TeamCreation`].
101 #[serde(default, skip_serializing_if = "Option::is_none")]
102 pub team_creation: Option<teams::TeamCreation>,
Merge main (membership, two-factor, GitHub repo roles) into tokens103 /// The roles the member holds besides `role`: billing manager,
104 /// security manager. Set when a user is resolved from credentials.
105 #[serde(default, skip_serializing_if = "Vec::is_empty")]
106 pub org_roles: Vec<OrgRole>,
107 /// What the workspace lets members (and repository admins) do. Set
108 /// when a user is resolved from credentials; absent means the
109 /// defaults. See [`members::MemberPrivileges`].
110 #[serde(default, skip_serializing_if = "Option::is_none")]
111 pub privileges: Option<MemberPrivileges>,
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them112}
113
114impl Membership {
115 /// A plain member of `slug`, as services act inside one workspace.
116 pub fn member(slug: impl Into<String>) -> Self {
117 Membership {
118 slug: slug.into(),
119 role: Role::Member,
120 name: None,
121 avatar: None,
122 base_permission: None,
Merge branch 'worktree-agent-ad7c6d88d93adc817'123 team_creation: None,
Merge main (membership, two-factor, GitHub repo roles) into tokens124 org_roles: Vec::new(),
125 privileges: None,
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them126 }
127 }
Merge main (membership, two-factor, GitHub repo roles) into tokens128
129 /// Whether the member holds `role` besides owner or member.
130 pub fn has(&self, role: OrgRole) -> bool {
131 self.org_roles.contains(&role)
132 }
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them133}
134
135/// What a set of credentials resolved to.
136#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
137#[serde(rename_all = "lowercase")]
138pub enum PrincipalKind {
139 /// A person's account.
140 #[default]
141 User,
142 /// A workspace, acting through one of its own access tokens. Its `id`
143 /// is the workspace's, its `username` the workspace's slug, and it is a
144 /// member of that workspace and no other.
145 Workspace,
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.146 /// A run's token: a sandbox g1t started (checks, the merge queue, a
147 /// merge check), acting through a token that lives as long as its run
148 /// and can do only what that token's scope lists, in one repository.
149 /// Its `username` is `g1t`. g1t no longer runs agents of its own; the
150 /// name stays because identity still issues run credentials with it and
151 /// historical rows written by `@g1t`'s agent were recorded as it.
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them152 Agent,
153 /// g1t itself: the platform acting on its own, as when it opens a
154 /// pull request to upgrade a vulnerable dependency or merges from the
155 /// queue. Never resolved from credentials: only services make one,
156 /// with [`User::system`]. Its `username` is `g1t`, which nobody can
157 /// register.
158 System,
159}
160
161/// g1t's own identity, as [`PrincipalKind::System`] work is recorded.
162pub mod system {
163 /// Its id wherever an author or actor id is stored.
164 pub const ID: &str = "g1t";
165 /// Its name, shown as the author of what it does.
166 pub const USERNAME: &str = "g1t";
167 /// The address on the commits it makes, which no mailbox receives.
168 pub const EMAIL: &str = "g1t@users.noreply.g1t.sh";
169 /// Ids that earlier versions stored for g1t's own actions, such as a
170 /// merge its settings made. Read as g1t too.
171 pub const LEGACY_IDS: [&str; 3] = ["g1t_policy", "svc_runner", "g1t_runner"];
172
173 /// Whether `id` is g1t's own.
174 pub fn is_system_id(id: &str) -> bool {
175 id == ID || LEGACY_IDS.contains(&id)
176 }
177}
178
179#[derive(Clone, Debug, Default, Serialize, Deserialize)]
180pub struct User {
181 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 managers182 /// Lowercased: what the person is found, linked and mentioned by.
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them183 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 managers184 /// The username as its owner wrote it (`Ana`), when that differs from
185 /// `username`: what pages show. Set on the signed-in person and on
186 /// people looked up by name; absent elsewhere, where `username` is shown.
187 #[serde(default, skip_serializing_if = "Option::is_none")]
188 pub display_username: Option<String>,
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them189 #[serde(default)]
190 pub kind: PrincipalKind,
191 /// Whether the account's email address has been confirmed. Unverified
192 /// accounts can sign in but cannot create or change anything.
193 #[serde(default)]
194 pub verified: bool,
195 /// The workspaces this user belongs to. Filled in when a user is
196 /// resolved from credentials, so any service can authorize from it.
197 #[serde(default)]
198 pub workspaces: Vec<Membership>,
199 /// The person's uploaded avatar: the SHA-256 of its bytes, served at
200 /// `/avatars/<avatar>`. Absent means the generated letter avatar.
201 #[serde(default, skip_serializing_if = "Option::is_none")]
202 pub avatar: Option<String>,
203 /// Set on an agent resolved from its token: who it acts for, with which
204 /// credential, and what it may do. See [`credentials`].
205 #[serde(default, skip_serializing_if = "Option::is_none")]
206 pub acting: Option<Box<credentials::Acting>>,
207 /// The repositories this user has been given a role on directly,
208 /// whether or not they belong to its workspace. Filled in with
209 /// `workspaces`; see [`access`].
210 #[serde(default, skip_serializing_if = "Vec::is_empty")]
211 pub grants: Vec<access::RepoGrant>,
212 /// Set on a user resolved from an access token: its scopes and the
213 /// workspaces or repositories it is limited to. Absent on a signed-in
214 /// session and on an agent (whose `acting` scope applies instead).
215 /// See [`scopes`].
216 #[serde(default, skip_serializing_if = "Option::is_none")]
217 pub token: Option<Box<scopes::TokenAccess>>,
Merge main (membership, two-factor, GitHub repo roles) into tokens218 /// The workspaces this person belongs to but cannot use until they
219 /// meet its policy, such as turning on two-factor authentication.
220 /// They are left out of `workspaces` and `grants` meanwhile. Set when
221 /// a person is resolved from a session.
222 #[serde(default, skip_serializing_if = "Vec::is_empty")]
223 pub held: Vec<members::PolicyHold>,
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them224}
225
226impl User {
227 /// g1t itself, acting in `workspace`: what the platform's own work,
228 /// such as security updates, is done and recorded as.
229 pub fn system(workspace: &str) -> User {
230 User {
231 id: system::ID.to_owned(),
232 username: system::USERNAME.to_owned(),
233 kind: PrincipalKind::System,
234 verified: true,
235 workspaces: vec![Membership::member(workspace.to_lowercase())],
236 ..User::default()
237 }
238 }
239
240 /// Whether this is g1t itself.
241 pub fn is_system(&self) -> bool {
242 self.kind == PrincipalKind::System
243 }
244
Merge email confirmation gate: a code and a link, nothing until confirmed (identity 0036)245 /// Whether this is a person whose account has not confirmed its email
246 /// address. Such an account can only confirm it (or change it, or sign
247 /// out): the site, the API, MCP and git refuse it everything else
248 /// ([`accounts::confirm_email_first`]).
249 pub fn awaits_confirmation(&self) -> bool {
250 self.kind == PrincipalKind::User && !self.verified
251 }
252
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them253 pub fn role_in(&self, slug: &str) -> Option<Role> {
254 self.workspaces
255 .iter()
256 .find(|membership| membership.slug == slug)
257 .map(|membership| membership.role)
258 }
259
260 pub fn is_member(&self, slug: &str) -> bool {
261 self.role_in(slug).is_some()
262 }
Merge main (membership, two-factor, GitHub repo roles) into tokens263
264 /// The membership in `slug`, if any.
265 pub fn membership(&self, slug: &str) -> Option<&Membership> {
266 self.workspaces.iter().find(|membership| membership.slug.eq_ignore_ascii_case(slug))
267 }
268
269 /// Whether this is a person who owns `slug`, or holds `role` in it.
270 pub fn owns_or_has(&self, slug: &str, role: OrgRole) -> bool {
271 self.membership(slug)
272 .is_some_and(|membership| membership.role == Role::Owner || membership.has(role))
273 }
274
275 /// Whether the user may manage `slug`'s billing: an owner or a billing
276 /// manager.
277 pub fn manages_billing(&self, slug: &str) -> bool {
278 self.owns_or_has(slug, OrgRole::BillingManager)
279 }
280
281 /// Whether the user may see and manage security across `slug`: an
282 /// owner or a security manager.
283 pub fn manages_security(&self, slug: &str) -> bool {
284 self.owns_or_has(slug, OrgRole::SecurityManager)
285 }
286
287 /// The workspace's member privileges as this user sees them: the
288 /// defaults when the membership does not say.
289 pub fn privileges_in(&self, slug: &str) -> MemberPrivileges {
290 self.membership(slug).and_then(|membership| membership.privileges).unwrap_or_default()
291 }
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them292}
293
294/// Who is asking. Every read and write in every service takes one.
295pub type Viewer = Option<User>;

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