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

Commit

Anyone can sign up for g1t: with an email address and a password, or with GitHub, and no invite. The switch that made registration invite-only is gone rather than flipped, so it cannot be turned back on by a setting: identity's REGISTRATION_MODE, INVITES_PER_USER, INVITE_STAFF_WORKSPACES and WAITLIST_NOTIFY_EMAIL vars, the same in the self-hosted compose file and configs, RegistrationMode in both contracts, and the registration call the site asked once a minute.

What existed only to gate sign-up goes with it. The sign-up page has no invite-code field and no Request access form; a link with a good invite code still goes to the invite's own page, and a code that is no good is dropped and the form shown. Settings → Invites and its menu entries, personal invites to g1t (create_invite, list_invites, revoke_invite, and GET/POST/DELETE /user/invites with their MCP actions), the five-invite allowance and staff grants, staff-minted invites, shared invite links, the waitlist, its confirmation email and staff summary, and the GitHub sign-up's invite step. Inviting someone into a workspace or onto a repository works as before and never costs an invite; repository invitations to a new address had still been charged to the inviter's allowance, which they no longer are. Sudo's Invites page keeps one list, every invite sent with an invitation, to search and revoke; an account made with a shared link still says Joined through its label. No data is deleted: the waitlist, invite_grants, shared_invites and shared_invite_uses tables, and invites.charged_to, charged_workspace_id and staff, stay as they are, unused or read only. Sign-ups with a password are now rate limited, since nothing else stood in the way of a script making accounts: 5 an hour per client address, 100 an hour together for requests that carry none, counted once the form is well formed and before anything is looked up or written. GitHub sign-up needs a GitHub account with a verified address and is not counted. Email confirmation before anything else, the honeypot and the invite-failure throttle stay. The deploy smoke test now checks the sign-up page and sends it an address identity refuses before counting. The docs say anyone can sign up (accounts and authentication, GitHub, workspaces, the quickstart, self-hosting, the API and MCP references, limitations), and the API reference is regenerated.

syntaqxcommitted Parent89697d2Browse files
67 files+72−38051 files not counted0/67 viewed
+5−5
88 # migrate pending D1 migrations, before any code, once check and plan pass
99 # core, edge, front the units of each stage, in jobs that share a build;
1010 # a stage starts only when the one before it succeeded
11−# smoke sign-in, sign-up and the waitlist still work on g1t.sh
11+# smoke sign-in and sign-up still work on g1t.sh
1212 #
1313 # Each run that deploys is one production deployment of g1t.sh, made by the
1414 # jobs that name `environment: production` (one per run, however many jobs):
301301 steps: *deploy
302302
303303 # Once everything has deployed: the ways in for someone new still work.
304− # The pages a visitor lands on load, and the waitlist form reaches
305− # identity, sent an address it refuses before keeping anything, so the
306− # real waitlist is never touched. scripts/ops/smoke.mjs.
304+ # The pages a visitor lands on load, and the sign-up form reaches
305+ # identity, sent an address it refuses before keeping or counting
306+ # anything, so no account is made. scripts/ops/smoke.mjs.
307307 smoke:
308308 name: Smoke
309309 needs: [check, plan, core, edge, front]
312312 timeout-minutes: 5
313313 steps:
314314 - uses: actions/checkout@v5
315− - name: Sign-in, sign-up and the waitlist work
315+ - name: Sign-in and sign-up work
316316 run: node scripts/ops/smoke.mjs
+1−7
8787 ),
8888 (
8989 "Invites",
90− "While g1t is invite-only, every new account needs an invite. Your invites, inviting people into a workspace by username or email, and answering the invitations to workspaces sent to you.",
90+ "Inviting people into a workspace by username or email, and answering the invitations to workspaces sent to you.",
9191 &[
92− Op::ListInvites,
93− Op::CreateInvite,
94− Op::RevokeInvite,
9592 Op::ListWorkspaceInvites,
9693 Op::InviteMember,
9794 Op::RevokeWorkspaceInvite,
678675 Op::ConfirmEmail => "Confirm an email address",
679676 Op::RemoveEmail => "Remove an email address",
680677 Op::UpdateEmailSettings => "Change your email settings",
681− Op::ListInvites => "List your invites",
682− Op::CreateInvite => "Create an invite",
683− Op::RevokeInvite => "Revoke an invite",
684678 Op::ListWorkspaceInvites => "List a workspace's invites",
685679 Op::InviteMember => "Invite someone to a workspace",
686680 Op::ListInvitations => "List your workspace invitations",
+2−67
133133 ConfirmEmail,
134134 RemoveEmail,
135135 UpdateEmailSettings,
136− ListInvites,
137− CreateInvite,
138− RevokeInvite,
139136 ListWorkspaceInvites,
140137 InviteMember,
141138 RevokeWorkspaceInvite,
724721 }
725722
726723 impl Op {
727− pub const ALL: [Op; 408] = [
724+ pub const ALL: [Op; 405] = [
728725 Op::Whoami,
729726 Op::GetWorkspace,
730727 Op::CreateWorkspace,
740737 Op::ConfirmEmail,
741738 Op::RemoveEmail,
742739 Op::UpdateEmailSettings,
743− Op::ListInvites,
744− Op::CreateInvite,
745− Op::RevokeInvite,
746740 Op::ListWorkspaceInvites,
747741 Op::InviteMember,
748742 Op::RevokeWorkspaceInvite,
11571151 Op::ConfirmEmail => "confirm_email",
11581152 Op::RemoveEmail => "remove_email",
11591153 Op::UpdateEmailSettings => "update_email_settings",
1160− Op::ListInvites => "list_invites",
1161− Op::CreateInvite => "create_invite",
1162− Op::RevokeInvite => "revoke_invite",
11631154 Op::ListWorkspaceInvites => "list_workspace_invites",
11641155 Op::InviteMember => "invite_member",
11651156 Op::RevokeWorkspaceInvite => "revoke_workspace_invite",
13811372 }
13821373 Op::UpdateEmailSettings => {
13831374 "Change what your addresses do; only the fields given change. `primary` is a confirmed address to make primary: account mail and password resets go there. `backup` is a confirmed address that also gets security notices, or an empty string for the primary only. Changing either needs your account `password`, and every confirmed address is told. `private_email` keeps your address off commits g1t makes for you (merges and changes made on the web, and agents' commits for you), which use your noreply address instead; `block_private_pushes` refuses pushes whose commits carry one of your addresses while it is private. People only."
1384− }
1385− Op::ListInvites => {
1386− "Your invites, newest first, and how many you have left. While g1t is invite-only, every new account needs an invite code. You may have 5 invites out at once: pending and used ones count, and one revoked or expired before it was used comes back. `allowance.limit` is null when you have no limit. `workspaces` lists the workspaces you own that were granted invites to share. A pending invite's `code` is shown to you. `status` is `pending`; `awaiting_confirmation` (used to make an account that has not confirmed its address yet); `awaiting_answer` (used to make an account that has yet to accept or decline the workspace it was invited to); `redeemed`; `declined` (its person declined the workspace); `expired`; or `revoked`. An invite that brings someone into a workspace names it in `workspace`, with the `role` it joins with and, once known, the account it is for in `invitee`."
13871375 }
1388− Op::CreateInvite => {
1389− "Make an invite. With `email`, it is sent there and only that address can use it; without, anyone with the code can, once. It works for 30 days. With `workspace`, the new account is brought into that workspace: once it confirms its address it gets an invitation to join as a member, which it accepts or declines, and no workspace of its own is made for it. That must be a workspace you own on the g1t plan; a free workspace is refused with `payment_required` (402). Without `workspace`, the new account gets a free workspace of its own. It uses one of your invites, or with `charge_workspace`, one of the invites g1t granted that workspace (its owners only). Returns the invite with its `code`; the link is https://g1t.sh/invite/<code>. People only: an agent's token or a workspace's token cannot make invites."
1390− }
1391− Op::RevokeInvite => {
1392− "Revoke a pending invite you made, or one made for a workspace you own. It stops working at once, and the invite comes back to whoever it was charged to."
1393− }
13941376 Op::ListWorkspaceInvites => {
13951377 "The invites made for a workspace, newest first, with each pending one's `code`. Owners only."
13961378 }
13971379 Op::InviteMember => {
1398− "Invite someone into a workspace, by `username` or by `email`. Nobody joins without saying yes: they get an invitation to accept or decline, and join with `role` (`member` unless you give `owner`) when they accept. By `username`, the account gets the invitation in its inbox and by email, and it costs nothing. By `email`, it always makes an invite bound to that address and emails it the link, so the answer never says whether the address has a g1t account. Without one, the link makes the account, which is invited once it confirms its address; while g1t is invite-only that uses one of the workspace's granted invites, or else one of yours, and once anyone can sign up it costs nothing. With one, it costs nothing. Refused with `409` when the person is already a member or already has a pending invitation to the workspace. Owners only. A free workspace cannot invite anyone: this is refused with `payment_required` (402) until it starts the g1t plan, and an invite sent before cannot be accepted until then."
1380+ "Invite someone into a workspace, by `username` or by `email`. Nobody joins without saying yes: they get an invitation to accept or decline, and join with `role` (`member` unless you give `owner`) when they accept. By `username`, the account gets the invitation in its inbox and by email, and it costs nothing. By `email`, it always makes an invite bound to that address and emails it the link, so the answer never says whether the address has a g1t account. Without one, the link makes the account, which is invited once it confirms its address. Refused with `409` when the person is already a member or already has a pending invitation to the workspace. Owners only. A free workspace cannot invite anyone: this is refused with `payment_required` (402) until it starts the g1t plan, and an invite sent before cannot be accepted until then."
13991381 }
14001382 Op::RevokeWorkspaceInvite => "Revoke a workspace's pending invite. Owners only.",
14011383 Op::ListInvitations => {
20071989 }),
20081990 &[],
20091991 ),
2010− Op::ListInvites => object(json!({}), &[]),
2011− Op::CreateInvite => object(
2012− json!({
2013− "email": {
2014− "type": "string",
2015− "description": "Only this address can use it, and it is emailed there. Left out, anyone with the code can.",
2016− },
2017− "workspace": {
2018− "type": "string",
2019− "description": "The workspace the new account is invited to, by slug. Once it confirms its address it gets an invitation to join as a member, and no workspace of its own. One you own, on the g1t plan.",
2020− },
2021− "charge_workspace": {
2022− "type": "string",
2023− "description": "Use one of the invites g1t granted this workspace instead of yours, by slug. Owners only.",
2024− },
2025− }),
2026− &[],
2027− ),
2028− Op::RevokeInvite => object(
2029− json!({ "id": { "type": "string", "description": "The invite's id, such as inv_01k…" } }),
2030− &["id"],
2031− ),
20321992 Op::ListWorkspaceInvites => object(json!({ "workspace": workspace_schema() }), &["workspace"]),
20331993 Op::InviteMember => object(
20341994 json!({
35963556 | Op::ConfirmEmail
35973557 | Op::RemoveEmail
35983558 | Op::UpdateEmailSettings
3599− | Op::ListInvites
3600− | Op::CreateInvite
3601− | Op::RevokeInvite
36023559 | Op::ListWorkspaceInvites
36033560 | Op::InviteMember
36043561 | Op::RevokeWorkspaceInvite
39103867 "privateEmail": input["private_email"].as_bool(),
39113868 "blockPrivatePushes": input["block_private_pushes"].as_bool(),
39123869 "reauth": { "password": optional_text(input, "password") },
3913− }),
3914− )
3915− .await
3916− }
3917− Op::ListInvites => {
3918− let overview: g1t_contracts::identity::InvitesOverview =
3919− g1t_kit::call(identity, "list_invites", &json!({ "user": actor() })).await?;
3920− ok(&overview)
3921− }
3922− Op::CreateInvite => {
3923− pass(
3924− identity,
3925− "create_invite",
3926− &json!({
3927− "user": actor(),
3928− "email": optional_text(input, "email"),
3929− "workspace": optional_text(input, "charge_workspace"),
3930− "join": optional_text(input, "workspace"),
3931− "surface": services.audit.surface,
39323870 }),
39333871 )
39343872 .await
3935− }
3936− Op::RevokeInvite => {
3937− pass(identity, "revoke_invite", &json!({ "user": actor(), "id": text(input, "id") })).await
39383873 }
39393874 Op::ListWorkspaceInvites => {
39403875 pass(identity, "workspace_invites", &json!({ "slug": workspace(), "viewer": viewer })).await
+0−108
383383 },
384384 "notes": "Only the fields given change. `primary` and `backup` need `password`; `private_email` and `block_private_pushes` do not."
385385 },
386− "list_invites": {
387− "response": {
388− "mode": "invite",
389− "allowance": {
390− "limit": 5,
391− "used": 2,
392− "remaining": 3
393− },
394− "workspaces": [
395− {
396− "slug": "acme-labs",
397− "allowance": {
398− "limit": 20,
399− "used": 4,
400− "remaining": 16
401− }
402− }
403− ],
404− "invites": [
405− {
406− "id": "inv_01kp2x7m8n9q0r1s2t3v4w5x6y",
407− "code": "g1t-k7m2-q9xd-4hpw-…",
408− "hint": "g1t-k7m2",
409− "email": "ada@example.com",
410− "kind": "account",
411− "workspace": null,
412− "status": "pending",
413− "charged_to": "user",
414− "invited_by": "syntaqx",
415− "redeemed_by": null,
416− "created_at": "2026-10-05T17:00:00.000Z",
417− "expires_at": "2026-11-04T17:00:00.000Z",
418− "redeemed_at": null,
419− "revoked_at": null,
420− "invitee": null,
421− "role": null
422− },
423− {
424− "id": "inv_01kp1v3c4d5e6f7g8h9j0k1m2n",
425− "code": null,
426− "hint": "g1t-p3rt",
427− "email": null,
428− "kind": "account",
429− "workspace": null,
430− "status": "redeemed",
431− "charged_to": "user",
432− "invited_by": "syntaqx",
433− "redeemed_by": "grace",
434− "created_at": "2026-10-02T09:12:40.000Z",
435− "expires_at": "2026-11-01T09:12:40.000Z",
436− "redeemed_at": "2026-10-02T11:30:05.000Z",
437− "revoked_at": null,
438− "invitee": "grace",
439− "role": null
440− }
441− ]
442− },
443− "notes": "`allowance.limit` and `allowance.remaining` are null when you have no limit. A revoked or expired invite that was never used is not counted. `status` is `pending`, `awaiting_confirmation`, `awaiting_answer` (the account it made has yet to accept or decline the workspace in `workspace`), `redeemed`, `declined`, `expired` or `revoked`. Ask for more at hey@flagon.io with the subject `[g1t Invites]`. See [Invites](/guides/authentication/#invites)."
444− },
445− "create_invite": {
446− "request": {
447− "email": "ada@example.com",
448− "workspace": "acme-labs"
449− },
450− "response": {
451− "id": "inv_01kp2x7m8n9q0r1s2t3v4w5x6y",
452− "code": "g1t-k7m2-q9xd-4hpw-…",
453− "hint": "g1t-k7m2",
454− "email": "ada@example.com",
455− "kind": "account",
456− "workspace": "acme-labs",
457− "status": "pending",
458− "charged_to": "user",
459− "invited_by": "syntaqx",
460− "redeemed_by": null,
461− "created_at": "2026-10-05T17:00:00.000Z",
462− "expires_at": "2026-11-04T17:00:00.000Z",
463− "redeemed_at": null,
464− "revoked_at": null,
465− "invitee": null,
466− "role": "member"
467− },
468− "notes": "`workspace` brings the new account into a workspace you own: once it confirms its address it gets an invitation to join as a member, which it accepts or declines, and no workspace of its own is made for it. Leave `workspace` out and the new account gets a free workspace of its own. A workspace on the free plan cannot bring anyone in: `402` with `payment_required`, until it starts the g1t plan. `charge_workspace` is separate: it uses one of the invites g1t granted that workspace instead of one of yours, and works with or without `workspace`. Refused with `402` (`limit`) when you have no invites left, with `409` when you already have a pending invite for that address or it already has a g1t account, and with `403` for an agent's or a workspace's token. The code is returned in full; send people the link `https://g1t.sh/invite/<code>`."
469− },
470− "revoke_invite": {
471− "response": {
472− "id": "inv_01kp2x7m8n9q0r1s2t3v4w5x6y",
473− "code": null,
474− "hint": "g1t-k7m2",
475− "email": "ada@example.com",
476− "kind": "account",
477− "workspace": null,
478− "status": "revoked",
479− "charged_to": "user",
480− "invited_by": "syntaqx",
481− "redeemed_by": null,
482− "created_at": "2026-10-05T17:00:00.000Z",
483− "expires_at": "2026-11-04T17:00:00.000Z",
484− "redeemed_at": null,
485− "revoked_at": "2026-10-06T08:00:00.000Z",
486− "invitee": null,
487− "role": null
488− }
489− },
490386 "list_workspace_invites": {
491387 "response": [
492388 {
497393 "kind": "account",
498394 "workspace": "acme-labs",
499395 "status": "pending",
500− "charged_to": "workspace",
501396 "invited_by": "syntaqx",
502397 "redeemed_by": null,
503398 "created_at": "2026-10-05T17:00:00.000Z",
515410 "kind": "workspace",
516411 "workspace": "acme-labs",
517412 "status": "pending",
518− "charged_to": "none",
519413 "invited_by": "syntaqx",
520414 "redeemed_by": null,
521415 "created_at": "2026-10-05T17:00:00.000Z",
540434 "kind": "workspace",
541435 "workspace": "acme-labs",
542436 "status": "pending",
543− "charged_to": "none",
544437 "invited_by": "syntaqx",
545438 "redeemed_by": null,
546439 "created_at": "2026-10-05T17:00:00.000Z",
561454 "kind": "account",
562455 "workspace": "acme-labs",
563456 "status": "revoked",
564− "charged_to": "workspace",
565457 "invited_by": "syntaqx",
566458 "redeemed_by": null,
567459 "created_at": "2026-10-05T17:00:00.000Z",
+1−2
214214 through::<g1t_contracts::accounts::AccountEmails>(op, sent)
215215 }
216216 Op::ConfirmEmail => through::<g1t_contracts::accounts::EmailConfirmed>(op, sent),
217− Op::ListInvites => through::<g1t_contracts::identity::InvitesOverview>(op, sent),
218− Op::CreateInvite | Op::RevokeInvite | Op::InviteMember | Op::RevokeWorkspaceInvite => {
217+ Op::InviteMember | Op::RevokeWorkspaceInvite => {
219218 through::<g1t_contracts::identity::Invite>(op, sent)
220219 }
221220 Op::ListWorkspaceInvites => through::<Vec<g1t_contracts::identity::Invite>>(op, sent),
+0−3
5252 route("POST", "/user/emails/confirm", Op::ConfirmEmail, &[]),
5353 route("DELETE", "/user/emails/:email", Op::RemoveEmail, &[]),
5454 route("PATCH", "/user/email-settings", Op::UpdateEmailSettings, &[]),
55− route("GET", "/user/invites", Op::ListInvites, &[]),
56− route("POST", "/user/invites", Op::CreateInvite, &[]),
57− route("DELETE", "/user/invites/:id", Op::RevokeInvite, &[]),
5855 // Invitations to workspaces waiting for your answer.
5956 route("GET", "/user/invitations", Op::ListInvitations, &[]),
6057 route("POST", "/user/invitations/:id/accept", Op::AcceptInvitation, &[]),
+1−4
578578 Tool {
579579 name: "account",
580580 title: "Your account",
581− description: "Who this token acts as and its workspaces (`whoami`), your email addresses, your invites, and invitations to workspaces and repositories waiting for you.",
581+ description: "Who this token acts as and its workspaces (`whoami`), your email addresses, and invitations to workspaces and repositories waiting for you.",
582582 default_action: Some("whoami"),
583583 actions: &[
584584 a("whoami", Op::Whoami, "Who the token acts as, and its workspaces"),
587587 a("confirm_email", Op::ConfirmEmail, "Confirm an address with the code from its email"),
588588 a("remove_email", Op::RemoveEmail, "Remove an address"),
589589 a("update_email_settings", Op::UpdateEmailSettings, "Primary, backup and privacy"),
590− a("list_invites", Op::ListInvites, "Your invites to g1t"),
591− a("create_invite", Op::CreateInvite, "Make an invite"),
592− a("revoke_invite", Op::RevokeInvite, "Revoke one"),
593590 a("list_workspace_invitations", Op::ListInvitations, "Invitations to workspaces for you"),
594591 a("accept_workspace_invitation", Op::AcceptInvitation, "Accept one and join"),
595592 a("decline_workspace_invitation", Op::DeclineInvitation, "Decline one"),
+0−5
489489
490490 ## Accounts, status and self-hosting
491491
492−### Sign-up needs an invite
493−
494−g1t is invite-only for now. See [Invites](/guides/authentication/#invites).
495−**Status.** Opening sign-up is planned.
496−
497492 ### Tokens for one workspace you belong to
498493
499494 A personal access token can be made for one workspace only when you are a
+44−144
11 ---
22 title: Accounts and authentication
3−description: Accounts, invites, email addresses, confirming them, two-factor authentication and recovery codes, personal access tokens and their permissions and scopes, a workspace's rules for tokens, OAuth, signing in from a tool, password reset, your security log and deleting your account.
3+description: Creating an account, invitations, email addresses, confirming them, two-factor authentication and recovery codes, personal access tokens and their permissions and scopes, a workspace's rules for tokens, OAuth, signing in from a tool, password reset, your security log and deleting your account.
44 ---
55
66 ## Creating an account
77
8−g1t is invite-only for now: to make an account you need an
9−[invite](#invites). Open the link in your invite, or enter its code at
10−[g1t.sh/register](https://g1t.sh/register). Without one, ask for access
11−on the same page.
8+Anyone can make an account at [g1t.sh/register](https://g1t.sh/register),
9+with an email address and a password or with **Continue with GitHub**. No
10+invite is needed. If someone invited you into a workspace or onto a
11+repository, open the link in their invitation instead: it signs you up and
12+takes you to what you were invited to (see [invites](#invites)).
1213
1314 Usernames are letters, digits and single hyphens, 1 to 39 characters, not
1415 starting or ending with a hyphen. They keep the case you type: choose
4445 | Profile | [`/settings/profile`](https://g1t.sh/settings/profile) | Your picture, and your [public profile](/guides/workspaces/#profiles): name, pronouns, bio, location, website and time zone. |
4546 | Emails | [`/settings/emails`](https://g1t.sh/settings/emails) | Your [email addresses](#email-addresses), the backup address, and [keeping your address private](#keeping-your-address-private). |
4647 | Notifications | [`/settings/notifications`](https://g1t.sh/settings/notifications) | [Sounds and do not disturb](/guides/chat/#sounds-and-do-not-disturb), [pop-ups and browser notifications](/guides/chat/#notifications), and [what you are emailed for and how you watch repositories](/guides/notifications/#settings). |
47−| Invites to g1t | [`/settings/invites`](https://g1t.sh/settings/invites) | [Making, copying and revoking invites to g1t](#making-invites), while g1t is invite-only; after that, the invites you made. |
4848 | SSH keys | [`/settings/keys`](https://g1t.sh/settings/keys) | Public keys for [git over SSH](/guides/git/#ssh), each with when it was added and last used. |
4949 | Access tokens | [`/settings/tokens`](https://g1t.sh/settings/tokens) | Your [personal access tokens](#access-tokens): their permissions, where they reach, and when they expire. |
5050 | Integrations | [`/settings/integrations`](https://g1t.sh/settings/integrations) | [Your own integrations](/guides/integrations/#workspace-and-personal): what you have connected for yourself, in every workspace, and what is coming. |
129129
130130 ## Invites
131131
132−There are two kinds of invite, and they do different things:
133−
134−| | Invite to g1t | Invite to a workspace |
135−| --- | --- | --- |
136−| Made from | [Settings → Invites](https://g1t.sh/settings/invites), your own | **Invite** on the workspace's **Members** or **Invitations** page, by its owners |
137−| What it gives | One new account. It adds them to no workspace: the account gets a workspace of its own | An invitation to join that workspace, which they accept or decline |
138−| Someone without an account | Makes their account with it | Makes their account with it too, while g1t is invite-only, then answers the invitation |
139−| Someone already on g1t | Nothing: they have an account | The invitation, in their notifications and by email |
140−| Exists | Only while g1t is invite-only | Always |
141−| What its page and email say | "@syntaqx invited you to g1t" | "@syntaqx invited you to join Flagon, Inc. on g1t" |
132+Anyone can sign up without an invite. Invites are how people already on
133+g1t bring someone in:
142134
143−So you can invite someone to g1t without inviting them into any
144−workspace; an invite to g1t only adds them to a workspace when you tick
145−**Also invite them to a workspace** (see [making invites](#making-invites)).
135+- an owner's [invitation into a workspace](#inviting-someone-into-a-workspace),
136+ by username or by email address;
137+- an [invitation to collaborate on a repository](/guides/access-and-roles/),
138+ by username or by email address.
146139
147−While g1t is invite-only, every new account needs an invite code, such as
148−`g1t-k7m2-q9xd-…`. People already on g1t make them, and g1t sends them to
149−people who [asked for access](#asking-for-access). An invite:
140+Invited by username, the account gets the invitation in its notifications
141+and by email. Invited by an address that has no g1t account yet, the email
142+carries an invite code, such as `g1t-k7m2-q9xd-…`, in a link to
143+`g1t.sh/invite/<code>`. That invite:
150144
151−- works once, for one new account;
145+- works once, for the address it was sent to;
152146 - works for 30 days;
153−- when it was made for an email address, works only with that address;
154−- can be revoked by whoever made it until it is used, and after that until
155− the new account [confirms its email address](#confirming-your-email-address).
147+- can be revoked by whoever sent it (or the workspace's owners) until it is
148+ used, and after that until the new account
149+ [confirms its email address](#confirming-your-email-address).
156150
157151 ### Using an invite
158152
197191 invite is revoked or expires, or its workspace is deleted, before you
198192 confirm, your address is confirmed all the same and g1t tells you the
199193 invite no longer applies: ask whoever invited you to invite you again. A
200−code typed at [g1t.sh/register](https://g1t.sh/register) goes to the
201−same page.
194+link to [g1t.sh/register](https://g1t.sh/register) with a good invite code
195+goes to the same page.
202196
203197 An expired, revoked or used invite says which, and who sent it, so you
204−can ask them for a new one; or ask for access from the same page.
198+can ask them for a new one; or [sign up](https://g1t.sh/register) without
199+it.
205200
206201 ### Invites from your inbox
207202
208−When g1t emails an invite to an address (an invite you make for someone,
209−an owner's invite into a workspace or a repository, or an approved
210−[request for access](#asking-for-access)), the link in that email carries a
203+When g1t emails an invite to an address (an owner's invitation into a
204+workspace, or an invitation onto a repository), the link in that email carries a
211205 `proof` that only the email has: `g1t.sh/invite/<code>?proof=…`. Opening
212206 the link shows that you can read that inbox, so:
213207
218212 names is a [workspace invitation](#workspace-invitations) you accept or
219213 decline straight away, since nobody joins a workspace without saying yes.
220214
221−Anything else confirms the address the usual way, after you sign up: the
222−code typed at [g1t.sh/register](https://g1t.sh/register), an invite link
223−copied from **Settings → Invites** (whoever made the invite sees the code,
224−never the proof), an invite made for anyone with the link, or an invite
225−email sent before this existed. The proof is tied to one invite and its
215+Anything else confirms the address the usual way, after you sign up: an
216+invite link copied from the workspace's **Invitations** page (whoever sent
217+the invite sees the code, never the proof), or an invite email sent before
218+this existed. The proof is tied to one invite and its
226219 address, and stops working when the invite is used, revoked or expires.
227−
228−### Invite links for a group
229−
230−g1t sometimes hands one link to a group: an event's judges, readers of a
231−post, a community. It looks like
232−`https://g1t.sh/register?invite=g1t-k7m2-…` and opens sign-up with the
233−code filled in and the group named above the form, such as **Invited as
234−part of Launch week judges**.
235−
236−- **It makes your own account.** Each person who uses it gets a new
237− account, and then makes their own workspace. It does not add you to
238− anyone else's workspace; once you are in, a workspace's owners can add
239− you from its **Members** page.
240−- **It may be for some email domains only.** When it is, the email field
241− says which, such as `example.com`, and sign-up takes only an address
242− there. Use your address at that organization; you confirm it like any
243− other.
244−- **It works a set number of times, until a set day.** Once every place
245− is taken, or the day has passed, or g1t has stopped it, the link gets
246− the same answer as any invite that cannot be used. Ask whoever shared
247− it, or [ask for access](#asking-for-access).
248−
249−Using the link spends one place in the same step that makes your account,
250−so two people signing up at the same moment can never take more places
251−than it has. Anyone with an account can still [make invites](#making-invites)
252−of their own; group links are made by g1t staff only.
253−
254−### Making invites
255−
256−These are invites to g1t. They let one person make an account, and add
257−them to no workspace unless you say so.
258−
259−1. Open [Settings → Invites](https://g1t.sh/settings/invites) (**Invites
260− to g1t** in your settings and account menu).
261−2. Optionally enter the email address of the person you are inviting.
262− With one, g1t emails them the invite, and only that address can use it.
263− Without one, anyone with the link can, once.
264−3. Optionally tick **Also invite them to a workspace**, then choose the
265− workspace and the role (**Member** or **Owner**) they are invited with.
266− It is off to start with, and no workspace is chosen for you, not even
267− the one you are in.
268−4. Select **Create invite**, then copy the link.
269−
270−Left unticked, the invite is to g1t only: the new account gets a
271−[workspace of its own](#your-first-workspace). Ticked, the new account
272−gets a [workspace invitation](#workspace-invitations) to the workspace you
273−chose once its address is confirmed, and is not given a workspace of its
274−own. The list of workspaces holds the ones you can add members to: the ones
275−you own that are on the g1t plan. A workspace on the free plan cannot add
276−people, so it is not offered, and the form says so when it is the one you
277−are in.
278220
279−To bring someone into a workspace, you do not need an invite to g1t:
280−invite them from the workspace's **Members** page,
281−`g1t.sh/<workspace>/-/members`, instead (see
282−[inviting someone into a workspace](#inviting-someone-into-a-workspace)).
283−Settings → Invites links to the Members pages of the workspaces you own.
284−
285−Once anyone can sign up for g1t, there are no invites to g1t to make:
286−Settings → Invites keeps only the list of invites you already made, and
287−says that anyone can sign up now and that workspace invitations live on
288−each workspace's Invitations page. With no invites made, the page is not listed
289−in your settings or account menu.
290−
291−Each person can have **5** invites out at a time. Pending and used invites
292−count; an invite you revoke, or one that expires before anyone uses it,
293−comes back to you. The list under the form shows each invite's state:
294−pending, confirming their email (used to sign up by someone who has not
295−confirmed their address yet), waiting for them to accept (the account is
296−made and confirmed, and the workspace invitation waits for its answer),
297−joined (with the username of who joined), declined, expired or revoked. You
298−must confirm your email before you can make invites. An agent's token and
299−a workspace's token cannot make them.
300−
301221 ### Inviting someone into a workspace
302222
303223 An owner can invite someone into a workspace from its **Members and
308228 to accept or decline. When an address has no g1t account, the invitation
309229 also lets it make one first, and the invitation is answered once the
310230 account's address is confirmed (at once when it was made from the invite
311−email's link). While g1t is invite-only, that uses one invite: one of the
312−workspace's shared invites when it has any, otherwise one of yours. Once
313−anyone can sign up, it costs nothing. Inviting someone who is already on
314−g1t never costs anything.
231+email's link). Inviting someone costs nothing either way.
315232
316233 ### Workspace invitations
317234
336253
337254 - An account whose invite brings it into a workspace gets the invitation
338255 to it, and no workspace of its own.
339−- Every other account (signed up with a password, with GitHub, from a
340− shared invite link or an invite from g1t staff, or with an invite that
341− names no workspace) gets a workspace of its own, named for its username,
342− on the free plan. Rename it or start the plan on it whenever you like.
256+- Every other account (signed up with a password or with GitHub, or with
257+ an invite that names no workspace, such as one onto a repository) gets a
258+ workspace of its own, named for its username, on the free plan. Rename it or start the plan on it whenever you like.
343259
344260 Signed in without any workspace (you declined an invitation, or left the
345261 only workspace you were in), g1t shows **Create your workspace or ask to
346262 join one** in place of Mission control: the invitations waiting for you, if
347263 any, and the form to create a workspace. To join a team already on g1t,
348264 ask one of its owners to invite you by your username.
349−
350−### Need more invites?
351−
352−Write to [hey@flagon.io](mailto:hey@flagon.io?subject=%5Bg1t%20Invites%5D%20)
353−with the subject `[g1t Invites]` and say who you would like to bring. g1t
354−can give more invites to you, or to a workspace, whose owners then share
355−them. Invites given to a workspace appear under
356−[Settings → Invites](https://g1t.sh/settings/invites) for
357−each of its owners, as a choice of whose invites to use.
358−
359−### Asking for access
360265
361−Without an invite, [g1t.sh/register](https://g1t.sh/register) asks for your
362−email address and, if you like, what you will build. g1t emails that
363−address once to confirm you are on the list, and staff see the request
364−straight away. When they approve it, the invite comes to the same address,
365−sometimes with a note, and its link opens sign-up with the address filled
366−in. There is no fixed date: g1t opens up a few people at a time. Asking
367−again with the same address updates your request without another email; it
368−does not move you down the list.
369−
370266 ### Invites through the API
371267
372268 | Route | MCP tool and action | What it does |
373269 | --- | --- | --- |
374−| [`GET /user/invites`](/reference/api/invites/list-invites/) | `account` `list_invites` | Your invites and how many you have left |
375−| [`POST /user/invites`](/reference/api/invites/create-invite/) | `account` `create_invite` | Make an invite, optionally for one `email`; with `workspace` (a slug), the new account is invited to that workspace |
376−| [`DELETE /user/invites/{id}`](/reference/api/invites/revoke-invite/) | `account` `revoke_invite` | Revoke a pending invite, or one whose new account has not confirmed its address |
377270 | [`POST /workspaces/{workspace}/invitations`](/reference/api/invites/invite-member/) | `workspace` `invite_member` | Invite a `username` or an `email` into a workspace, with a `role`. Owners only. |
378271 | [`GET /user/invitations`](/reference/api/invites/list-invitations/) | `account` `list_workspace_invitations` | The workspace invitations waiting for your answer |
379272 | [`POST /user/invitations/{id}/accept`](/reference/api/invites/accept-invitation/) | `account` `accept_workspace_invitation` | Join the invitation's workspace with its role |
420313 - **The MCP server** answers `403` with the same message.
421314 - **Git** over HTTPS refuses pushes and fetches with your credentials, with
422315 the same message. Package registries treat them as wrong credentials.
423−- You cannot create a workspace, answer the invitation your invite brought, make
424− invites or tokens, or approve a tool's sign-in.
316+- You cannot create a workspace, answer the invitation your invite brought,
317+ invite anyone, make tokens, or approve a tool's sign-in.
425318
426319 You cannot make a token before you confirm, so the API and MCP refusals
427320 matter only for an account that made one before this rule existed.
12421135
12431136 ## Too many attempts
12441137
1245−g1t counts wrong passwords, on the sign-in page, for git over HTTPS and
1138+g1t counts sign-ups with a password from each network: after **5** in an
1139+hour, [g1t.sh/register](https://g1t.sh/register) answers "Too many accounts
1140+were made from your network in the last hour" until the hour is up. A form
1141+with a mistake in it (a username that cannot be used, an address that is
1142+not one, a short password) is not counted. Signing up with GitHub is not
1143+counted this way: it needs a GitHub account with a verified address.
1144+
1145+g1t also counts wrong passwords, on the sign-in page, for git over HTTPS and
12461146 when confirming it is you, against the account and against where they come
12471147 from. After 10 wrong passwords for one account in an hour, or 30 from one
12481148 place, g1t stops checking passwords for it for a minute, then twice as long
+5−4
2828 - **Password**: none. Sign in with GitHub, or set a password later with
2929 [Forgot your password](https://g1t.sh/forgot).
3030
31−g1t is invite-only for now. To create an account with GitHub, open the
32−invite link you were given and choose **Continue with GitHub** there, or
33−enter your invite code when g1t asks for it after GitHub. Signing in to an
34−account you already have needs no invite.
31+Anyone can create an account with GitHub: choose **Continue with GitHub**
32+on [g1t.sh/register](https://g1t.sh/register). If someone invited you into
33+a workspace or onto a repository, open their invite link and choose
34+**Continue with GitHub** there instead, so the new account gets the
35+invitation.
3536
3637 Signing in with GitHub does not start a trial or give your workspace
3738 compute. That works as it does for any account: see
+0−4
162162 | `MAILPIT_PORT` | `8025` | The port of the Mailpit inbox |
163163 | `MAIL_FROM` | `g1t <noreply@localhost>` | The sender of g1t's email |
164164 | `MAIL_URL` | `http://mailpit:8025` | The Mailpit server g1t sends mail through |
165−| `REGISTRATION_MODE` | `open` | `open`: anyone can make an account. `invite`: every new account needs an [invite](/guides/authentication/#invites), as on g1t.sh. |
166−| `INVITES_PER_USER` | `5` | How many invites each person can have out, while `REGISTRATION_MODE` is `invite` |
167−| `WAITLIST_NOTIFY_EMAIL` | (none) | Where a summary of new access requests goes, at most every 15 minutes. Empty sends none; requests still wait for you in the database. |
168165 | `S3_ENDPOINT`, `S3_BUCKET`, `S3_REGION`, `S3_ACCESS_KEY_ID`, `S3_SECRET_ACCESS_KEY` | the bundled RustFS, bucket `g1t-packages` | Where packages' files are kept: any S3-compatible store. Change the two keys before first start; RustFS is made with them. |
169166 | `S3_PUBLIC_ENDPOINT` | (none) | The store's address as clients reach it. When set, large layers are downloaded from it directly with a signed URL. |
170167 | `PACK_S3_BUCKET` | `g1t-git-packs` | The bucket on the same store that packs for fresh clones are kept in, so the next clone of the same commit is not built again. The bundled store deletes packs after 7 days, and uploads left unfinished after a day; on another store, give the bucket a lifecycle rule that does the same. |
174171 | `BACKUP_S3_BUCKET` | `g1t-backups` | The bucket on the same store that nightly repository backups (a `git bundle` of each repository whose branches or tags changed) are kept in. The bundles are cut by g1t's runner, which this installation does not run yet, so the bucket stays empty for now: copy the volumes, as below. |
175172 | `STATUS_PORT` | `8788` | The port the status page is published on |
176173 | `STATUS_PROBE_REPO` | (none) | A public repository, `workspace/repo`, whose branches the status page lists every minute as a clone would. Empty: git is not checked. |
177−| `INVITE_STAFF_WORKSPACES` | (none) | Workspace slugs, comma separated, whose owners can make invites without a limit. Set it to your own workspace before you switch to `invite`, so someone can invite the first people. |
178174 | `PHONE_PUSH` | `on` | `off`: send [the phone app](#the-phone-app) no notifications, so their words never pass through Expo's push service. Browser and desktop notifications are not affected. |
179175
180176 ## The phone app
+6−17
368368 without saying yes: an owner invites people, and each person accepts or
369369 declines.
370370
371−This is an invitation to join one workspace. It is not the same as an
372−invite to g1t, which only lets someone make an account:
373−
374−| | Invite to a workspace | Invite to g1t |
375−| --- | --- | --- |
376−| Where | **Invite** on the workspace's **Members** or **Invitations** page | [Settings → Invites](https://g1t.sh/settings/invites) |
377−| What they get | An invitation to join the workspace, to accept or decline | One new account, in no workspace but its own |
378−| Without an account | The invitation lets them sign up first, while g1t is invite-only | It lets them sign up |
379−| When | Always | Only while g1t is invite-only |
380−
381−To invite someone to g1t without adding them to your workspace, use
382−[Settings → Invites](/guides/authentication/#making-invites).
371+Anyone can make a g1t account without an invite, so to bring someone in
372+you invite them to the workspace; someone without an account signs up from
373+the invitation.
383374
384375 On the workspace's **Members** page, `g1t.sh/<workspace>/-/members`
385376 (**Workspace → Access → Members** in the sidebar), or on **Invitations**
404395 - **By email address**: g1t emails an invite that only that address can
405396 use. With a g1t account, it is a workspace invitation like the one above
406397 and costs nothing. Without one, the invitation also lets them make the
407− account first; while g1t is invite-only that uses one of the workspace's
408− granted invites, or else one of yours (see
409− [invites](/guides/authentication/#invites)), and once anyone can sign up
410− it costs nothing. The new account is then invited to the workspace, and
411− joins when it accepts. The page never says which it was.
398+ account first, and costs nothing (see
399+ [invites](/guides/authentication/#invites)). The new account is then
400+ invited to the workspace, and joins when it accepts. The page never says which it was.
412401
413402 The email names you and the workspace and links to the invite's page.
414403 Someone new signs up right there, with the invited address filled in; once
+2−2
2424
2525 1. **Create an account and a workspace**
2626
27− [Sign up](https://g1t.sh/register) with your invite (g1t is invite-only
28− for now; see [invites](/guides/authentication/#invites)) and confirm your
27+ [Sign up](https://g1t.sh/register) (or open the invite link someone sent
28+ you; see [invites](/guides/authentication/#invites)) and confirm your
2929 email with the code g1t sends it (or the link in the same email). Then create a
3030 **workspace**: it holds your channels, agents and repositories. See
3131 [workspaces](/guides/workspaces/).
+1−1
230230 | [Workspaces](/reference/api/workspaces/create-workspace/) | Creating a workspace. |
231231 | [Notifications](/reference/api/notifications/list-notifications/) | Your notifications: their threads, why you were told of each, marking them read, done, saved or snoozed, and what you subscribe to and watch. See [notifications](/guides/notifications/). |
232232 | [Billing](/reference/api/billing/get-usage/) | A workspace's usage by product, project and day, its budget, its AI credit, its invoices and its [AI Gateway](/guides/ai-gateway/) requests. See [usage and billing](/guides/usage-and-billing/). |
233−| [Invites](/reference/api/invites/list-invites/) | Your invites while g1t is invite-only, and inviting people into a workspace by email. |
233+| [Invites](/reference/api/invites/list-workspace-invites/) | Inviting people into a workspace by username or email, and answering the invitations sent to you. |
234234 | [Repositories](/reference/api/repositories/list-repos/) | A repository, how it handles pull requests, and its timeline. |
235235 | [Access](/reference/api/access/list-collaborators/) | Who has which role on a repository, invitations, outside collaborators, and a workspace's base permission. |
236236 | [Secret scanning](/reference/api/secret-scanning/list-secret-scanning-alerts/) | Secrets found in pushes and history, where each one is, bypassing push protection and reviewing bypass requests, validity checks, and custom patterns. See [secret protection](/guides/security/secret-protection/). |
+4−7
818818
819819 ## `account`
820820
821−Who the token acts as and its workspaces, your email addresses, your
822−invites while g1t is [invite-only](/guides/authentication/#invites), and
823−invitations to workspaces and repositories waiting for you. `whoami` is the default
821+Who the token acts as and its workspaces, your email addresses, and
822+[invitations](/guides/authentication/#invites) to workspaces and
823+repositories waiting for you. `whoami` is the default
824824 action, and needs no scope. An agent's token and a workspace's token cannot
825−use the email and invite actions. An account that has not confirmed its
825+use the email and invitation actions. An account that has not confirmed its
826826 email address gets `403` from every tool until it does; see
827827 [until you confirm](/guides/authentication/#until-you-confirm).
828828
834834 | [`confirm_email`](/reference/api/accounts/confirm-email/) | Confirm an address with the six-digit code from its email. See [confirming your email address](/guides/authentication/#confirming-your-email-address). | `code` | `account:write` |
835835 | [`remove_email`](/reference/api/accounts/remove-email/) | Remove an address; never the primary or the last confirmed one. | `email`, `password` | `account:write` |
836836 | [`update_email_settings`](/reference/api/accounts/update-email-settings/) | Change `primary` or `backup` (with `password`), `private_email` or `block_private_pushes`. See [email addresses](/guides/authentication/#email-addresses). | None | `account:write` |
837−| [`list_invites`](/reference/api/invites/list-invites/) | Your invites, newest first, and how many you have left. | None | `account:read` |
838−| [`create_invite`](/reference/api/invites/create-invite/) | Make an invite; with `email`, only that address can use it and it is emailed there. With `workspace`, the new account is invited to that workspace (one you own, on the g1t plan) once it confirms its address, instead of getting a workspace of its own. With `charge_workspace`, use that workspace's granted invites instead of yours. | None | `account:write` |
839−| [`revoke_invite`](/reference/api/invites/revoke-invite/) | Revoke a pending invite; it comes back to whoever it was charged to. | `id` | `account:write` |
840837 | [`list_workspace_invitations`](/reference/api/invites/list-invitations/) | The invitations to workspaces waiting for your answer, each with its `workspace`, the `role` it gives and who sent it. | None | `account:read` |
841838 | [`accept_workspace_invitation`](/reference/api/invites/accept-invitation/) | Accept one; you join the workspace at once with its role. | `id` | `account:write` |
842839 | [`decline_workspace_invitation`](/reference/api/invites/decline-invitation/) | Decline one; whoever sent it is told. | `id` | `account:write` |
+0−0

Binary or large file; its contents are not shown.

Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…

Comments

Sign in to comment.