g1t/crates/contracts/src/names.rs

114 lines3,359 bytesCodeBlame

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.

API and MCP server, Rust identity service, registration, site redesign1/// Routes and reserved words that may not be registered as usernames.
2const RESERVED: &[&str] = &[
Workspaces own repositories3 "api",
4 "mcp",
5 "login",
6 "logout",
7 "register",
8 "new",
9 "settings",
10 "search",
11 "admin",
12 "auth",
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look13 // g1t.sh/integrations/github/setup: where GitHub returns after an install.
14 "integrations",
Issues and pull requests replace intents and attempts15 "pulls",
16 "issues",
Workspaces own repositories17 "oauth",
18 "assets",
Workspace names and icons, and a component kit for every control19 "avatars",
Workspaces own repositories20 "docs",
21 "explore",
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent22 // g1t itself, and the name its agent once went by: everything g1t
23 // does is shown as `g1t`, so nobody else may be called either.
Workspaces own repositories24 "g1t",
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent25 "g1t-agent",
Workspaces own repositories26 "about",
27 "pricing",
28 "terms",
29 "privacy",
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look30 "policies",
31 "security",
Workspaces own repositories32 "help",
33 "support",
34 "status",
35 "blog",
36 "verify",
37 "forgot",
38 "reset",
39 "device",
40 "workspaces",
41 "u",
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look42 // g1t.sh/invite/<code>: invite links; and the waitlist.
43 "invite",
44 "invites",
45 "waitlist",
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member46 // g1t.sh/v2/: the container registry; `-` paths hold the others.
47 "v2",
API and MCP server, Rust identity service, registration, site redesign48];
49
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent50/// Whether `value`, whatever its case, is a name nobody can register or
51/// rename a workspace to: a route, or g1t's own.
52pub fn is_reserved_name(value: &str) -> bool {
53 let value = value.trim();
54 RESERVED.iter().any(|reserved| reserved.eq_ignore_ascii_case(value))
55}
56
57/// A username or workspace slug as someone typed it, trimmed and
58/// lowercased, if it can be registered: what signing up, signing up with
59/// GitHub and creating a workspace each take. None when it is malformed or
60/// reserved.
61pub fn claimable_namespace(value: &str) -> Option<String> {
62 let value = value.trim().to_lowercase();
63 is_valid_namespace(&value).then_some(value)
64}
65
API and MCP server, Rust identity service, registration, site redesign66/// Namespaces follow GitHub's rules: letters, digits and single hyphens,
67/// not starting or ending with a hyphen, at most 39 characters.
68pub fn is_valid_namespace(value: &str) -> bool {
69 let bytes = value.as_bytes();
70 !bytes.is_empty()
71 && bytes.len() <= 39
72 && bytes
73 .iter()
74 .all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || *byte == b'-')
75 && !value.starts_with('-')
76 && !value.ends_with('-')
77 && !value.contains("--")
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent78 && !is_reserved_name(value)
API and MCP server, Rust identity service, registration, site redesign79}
80
81pub fn is_valid_repo_name(value: &str) -> bool {
82 !value.is_empty()
83 && value.len() <= 100
84 && value.bytes().all(|byte| {
85 byte.is_ascii_lowercase() || byte.is_ascii_digit() || matches!(byte, b'.' | b'_' | b'-')
86 })
87 && !value.starts_with('.')
88 && !value.ends_with(".git")
Agents as a team: lifecycle, merge queue, billing and a new shell89 // `/<workspace>/-/…` holds the workspace's own pages.
90 && value != "-"
API and MCP server, Rust identity service, registration, site redesign91}
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn g1ts_own_names_are_reserved_in_any_case() {
99 for name in ["g1t", "G1T", "g1t-agent", "G1T-Agent", " g1t "] {
100 assert!(is_reserved_name(name), "{name}");
101 assert_eq!(claimable_namespace(name), None, "{name}");
102 }
103 assert!(!is_valid_namespace("g1t"));
104 assert!(!is_valid_namespace("g1t-agent"));
105 }
106
107 #[test]
108 fn names_near_g1ts_are_anyones() {
109 assert!(!is_reserved_name("g1t-agents"));
110 assert_eq!(claimable_namespace("G1T-Bot").as_deref(), Some("g1t-bot"));
111 assert_eq!(claimable_namespace(" Ana ").as_deref(), Some("ana"));
112 assert_eq!(claimable_namespace("an--a"), None);
113 }
114}