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
116 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 Packages page names every registry it has1// Namespaces follow GitHub's rules (no leading, trailing or doubled hyphens),
2// so "--" can never appear inside one.
3const NAMESPACE = /^[a-z0-9](?:[a-z0-9]|-(?=[a-z0-9])){0,38}$/;
4const REPO_NAME = /^[a-z0-9._-]{1,100}$/;
5
6/** Routes and reserved words that may not be registered as usernames. */
7const RESERVED = new Set([
8 "api", "mcp", "login", "logout", "register", "new", "settings", "search",
Merge email confirmation gate: a code and a link, nothing until confirmed (identity 0036)9 "admin", "auth", "integrations", "pulls", "issues", "verify", "confirm-email", "forgot", "reset", "device", "workspaces", "u", "oauth", "assets", "avatars", "docs", "explore", "about", "pricing",
The Packages page names every registry it has10 // g1t itself, and the name its agent once went by: everything g1t does is
Merge account deletion: soft delete for 30 days, staff restore and purge, ghost for what remains (identity 0037)11 // shown as `g1t`, so nobody else may be called either. `ghost` wrote what
12 // a deleted account wrote (`GHOST_USERNAME`).
13 "g1t", "g1t-agent", "ghost",
The Packages page names every registry it has14 // Trust pages on g1t.sh, and names kept for them.
15 "policies", "security", "support", "status", "terms", "privacy", "help", "blog",
16 // Invite links, and the waitlist.
17 "invite", "invites", "waitlist",
Merge workspace invitations: nobody joins a workspace without saying yes, people are found by username, your own invites can bring someone in, and nobody is left without a workspace (identity 0040)18 // g1t.sh/invitations: the workspace invitations waiting for an answer.
19 "invitations",
The Packages page names every registry it has20 // The container registry, at g1t.sh/v2/.
21 "v2",
Inbox: a bell in the top bar opens it beside the page, and /inbox holds it all22 // g1t.sh/inbox, and the name it might also go by.
23 "inbox", "notifications",
preparing for cloud work24 // g1t.sh/download, the desktop app; g1t.sh/downloads/, the releases it and the runner come from.
25 "download", "downloads",
Merge main into rm-agents: mirroring removal, open signups, free-tier limits, the g1t CLI and runner fixes, with the agent removal kept. The CLI's table of operations is regenerated from the API without the agent, customize and AI credit operations; no CLI command used them.26 // g1t.sh/install and g1t.sh/install.ps1, the CLI's install scripts.
27 "install",
The Packages page names every registry it has28]);
29
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.30/**
31 * The GitHub accounts whose actions workflows use most. `uses:
32 * actions/setup-node@v4` means GitHub's `actions`, so nobody may register
33 * these on g1t; an account that already has one keeps it. The list is
34 * crates/contracts/src/names.rs's `ACTION_OWNERS`.
35 */
36const ACTION_OWNERS = new Set([
37 "actions", "actions-ecosystem", "actions-rs", "amannn", "anchore", "appleboy", "aquasecurity",
38 "arduino", "astral-sh", "aws-actions", "azure", "browser-actions", "bufbuild", "cachix",
39 "changesets", "chromaui", "cloudflare", "codecov", "conda-incubator", "coursier", "crazy-max",
40 "cypress-io", "dawidd6", "denoland", "dependabot", "dessant", "determinatesystems",
41 "devcontainers", "digitalocean", "docker", "dorny", "dtolnay", "endbug", "erlef",
42 "firebaseextended", "fluxcd", "getsentry", "github", "golangci", "google-github-actions",
43 "googleapis", "goreleaser", "gradle", "gradle-update", "hadolint", "hashicorp",
44 "haskell-actions", "hecrj", "helm", "ilammy", "jamesives", "jetbrains", "julia-actions",
45 "kubernetes-sigs", "lukka", "marocchino", "microsoft", "mikepenz", "mozilla-actions", "msys2",
46 "mxschmitt", "ncipollo", "netlify", "nick-fields", "nwtgck", "octokit", "ossf", "oven-sh",
47 "peaceiris", "peter-evans", "pnpm", "pre-commit", "pypa", "r-lib", "release-drafter",
48 "renovatebot", "reviewdog", "rhysd", "ruby", "rust-lang", "sbt", "shivammathur", "sigstore",
49 "slackapi", "slsa-framework", "snyk", "softprops", "sonarsource", "stefanzweifel",
50 "step-security", "styfle", "subosito", "supabase", "super-linter", "superfly", "svenstaro",
51 "swatinem", "taiki-e", "tj-actions", "treosh", "vercel", "webfactory",
52]);
53
54/** Whether `value`, whatever its case, names a well-known GitHub action owner. */
55export function isActionOwnerName(value: string): boolean {
56 return ACTION_OWNERS.has(value.trim().toLowerCase());
57}
58
59/** Whether a person or workspace may take `value` as its name now: valid, and no well-known action owner's. */
60export function isClaimableName(value: string): boolean {
61 return isValidNamespace(value) && !isActionOwnerName(value);
62}
63
The Packages page names every registry it has64/** Whether `value`, whatever its case, is a name nobody can register: a route, or g1t's own. */
65export function isReservedName(value: string): boolean {
66 return RESERVED.has(value.trim().toLowerCase());
67}
68
69export function isValidNamespace(value: string): boolean {
Merge branch 'worktree-agent-a8385d293d42c913a'70 return isNamespaceShaped(value) && !isReservedName(value);
71}
72
73/**
74 * Whether `value` has a namespace's shape, reserved or not: what a
75 * workspace's old name or an alias staff set (such as `g1t`) can be.
76 */
77export function isNamespaceShaped(value: string): boolean {
78 return NAMESPACE.test(value);
The Packages page names every registry it has79}
80
One kind of access token; presence and status; usernames keep their case; the tour is a miniature of the real app; icons for password managers81/**
82 * Usernames: letters of either case, digits and single hyphens, not
83 * starting or ending with a hyphen, 1 to 39 characters, never reserved in
84 * any case. The case is kept for showing; everything finds a person by the
85 * name lowercased (`canonicalUsername`), so `Ana` and `ana` are one name.
86 */
87const USERNAME = /^[A-Za-z0-9](?:[A-Za-z0-9]|-(?=[A-Za-z0-9])){0,38}$/;
88
89/** The `pattern` a username field takes in a form: the same rule, for the browser. */
90export const USERNAME_PATTERN = "[A-Za-z0-9](?:[A-Za-z0-9]|-(?=[A-Za-z0-9]))*";
91
92export function isValidUsername(value: string): boolean {
93 const name = value.trim();
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.94 return USERNAME.test(name) && !isReservedName(name) && !isActionOwnerName(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 managers95}
96
97/** The name a person is found, linked and mentioned by: lowercased. */
98export function canonicalUsername(value: string): string {
99 return value.trim().toLowerCase();
100}
101
102/** How a person's username shows: as they wrote it, or as it is kept. */
103export function shownUsername(person: { username: string; display_username?: string | null; displayUsername?: string | null }): string {
104 const display = person.display_username ?? person.displayUsername;
105 return display && display.toLowerCase() === person.username.toLowerCase() ? display : person.username;
106}
107
The Packages page names every registry it has108export function isValidRepoName(value: string): boolean {
109 return (
110 REPO_NAME.test(value) &&
111 !value.startsWith(".") &&
112 !value.endsWith(".git") &&
113 // `/<workspace>/-/…` holds the workspace's own pages.
114 value !== "-"
115 );
116}

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