Run g1t yourself
Start the core forge on your own machine with Docker Compose.
g1t is MIT licensed. You can run the core forge on your own machine: accounts, workspaces, repositories, git over HTTP, issues and pull requests, and the site to browse them. Your repositories are plain bare git repositories on a Docker volume.
This is an early version. It is for trying g1t out and for small teams on a private network, not yet for an installation on the open internet.
What works and what is off
Section titled “What works and what is off”| Feature | Self-hosted |
|---|---|
| Sign up, sign in, email confirmation | Works. Mail goes to the bundled Mailpit inbox. |
| Workspaces, members, access tokens | Works |
| Repositories: create, push and clone over HTTP, browse code, commits | Works |
| Issues, comments, labels | Works |
| Site search | Works |
| A status page of your own | Works, at http://localhost:8788 (below) |
| Webhooks, integrations | Run, but scheduled retries do not (see below) |
| Sign in with GitHub, import from GitHub | Off until you register a GitHub App of your own (below). Mirrors sync with Sync now: GitHub’s webhook needs the REST API. |
| g1t agents, plans, reviews by agents | Off |
| Context hub search | Off |
Deployments on g1t.page |
Off |
| Billing | Off. Nothing is charged, and no usage limit stops work. |
Git over SSH, the REST API, MCP and the g1t CLI |
Not available yet |
| Scheduled jobs (webhook retries, Actions schedules) | Not run yet |
Before you start
Section titled “Before you start”- Docker with Compose v2 (
docker compose version). - About 4 GB of free disk space for the images.
- Ports 8787, 8788 and 8025 free on your machine.
Start g1t
Section titled “Start g1t”-
Get the source:
git clone https://g1t.sh/flagon-io/g1t.gitcd g1t -
Build and start it. The first build compiles every service and takes a while:
docker compose -f deploy/self-host/docker-compose.yml up --build -d -
Open http://localhost:8787 and create an account.
-
Open the Mailpit inbox at http://localhost:8025 and follow the link in the confirmation email.
-
Create a workspace, then a repository.
Push and clone
Section titled “Push and clone”The remote is the site’s address, then the workspace and repository:
git remote add origin http://localhost:8787/<workspace>/<repo>.gitgit push -u origin mainGit asks for a username and password: use your g1t username and password, or an access token, as described in Git. Public repositories clone without signing in:
git clone http://localhost:8787/<workspace>/<repo>.gitCheck an installation
Section titled “Check an installation”deploy/self-host/smoke.sh signs up a new account, confirms it through
Mailpit, makes a workspace and a repository, pushes, clones, opens an issue
and reads the code back through the site:
bash deploy/self-host/smoke.shIt prints All checks passed when every step worked.
Settings
Section titled “Settings”Set these in the environment, or in a .env file next to
docker-compose.yml:
| Variable | Default | What it does |
|---|---|---|
PUBLIC_URL |
http://localhost:8787 |
The address people use. Links in email point here. |
G1T_PORT |
8787 |
The port the site is published on |
MAILPIT_PORT |
8025 |
The port of the Mailpit inbox |
MAIL_FROM |
g1t <noreply@localhost> |
The sender of g1t’s email |
MAIL_URL |
http://mailpit:8025 |
The Mailpit server g1t sends mail through |
REGISTRATION_MODE |
open |
open: anyone can make an account. invite: every new account needs an invite, as on g1t.sh. |
INVITES_PER_USER |
5 |
How many invites each person can have out, while REGISTRATION_MODE is invite |
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. |
STATUS_PORT |
8788 |
The port the status page is published on |
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. |
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. |
The status page
Section titled “The status page”The status service runs the same status page as
status.g1t.sh, in a process of its own, so it keeps
answering when the site does not. Open
http://localhost:8788.
Every minute it loads the site’s sign-in page from inside Compose, and,
with STATUS_PROBE_REPO set, lists that repository’s branches. It keeps
90 days of history on its own volume, g1t-status. Parts an installation
of your own does not run (the API, MCP, docs, deployments, the model
proxy and billing) are left off its page.
The links to Status in the site’s footer and account menu still point to status.g1t.sh; pointing them at your own status page is not a setting yet.
To deliver email to real inboxes, have Mailpit relay it through your SMTP
server. The settings are in docker-compose.yml, under mailpit.
Sign-in cookies are marked Secure. Browsers accept them on
http://localhost. On any other address, put g1t behind HTTPS (a reverse
proxy such as Caddy or nginx with a certificate) and set PUBLIC_URL to
the https:// address.
Sign in with GitHub and import from GitHub
Section titled “Sign in with GitHub and import from GitHub”g1t.sh’s GitHub App works only for g1t.sh. To offer Continue with GitHub and Import from GitHub on your own g1t, register an app of your own. Without one, neither button appears.
-
On GitHub, open Settings → Developer settings → GitHub Apps → New GitHub App (or the same under an organization’s settings).
-
Fill it in, with
PUBLIC_URLstanding for your g1t’s address:Setting Value Callback URL PUBLIC_URL/auth/github/callbackExpire user authorization tokens On Request user authorization (OAuth) during installation Off Enable Device Flow Off Setup URL PUBLIC_URL/integrations/github/setupRedirect on update On Webhook Off for now: a self-hosted g1t does not serve the API, where GitHub’s deliveries arrive. Mirrors sync with Sync now. Repository permissions Contents: Read and write; Metadata: Read; Issues: Read Account permissions Email addresses: Read -
Create it, then on its page note the App ID, the Client ID and the slug (the last part of its public address,
github.com/apps/<slug>). Generate a client secret and a private key, which downloads a.pemfile. -
Set these before starting g1t, in the environment or in
.env:Variable Value GITHUB_APP_IDThe App ID GITHUB_APP_SLUGThe slug GITHUB_APP_CLIENT_IDThe Client ID GITHUB_APP_CLIENT_SECRETThe client secret GITHUB_APP_PRIVATE_KEYThe .pemfile’s contents, as downloaded. Line breaks may be written as `
. | | GITHUB_APP_WEBHOOK_SECRET` | Only once the API is served: the webhook secret |
- Restart g1t:
docker compose -f deploy/self-host/docker-compose.yml up -d.
g1t makes its own key for the GitHub tokens it keeps (IDENTITY_KEY, in
the g1t-data volume) on first start. What the app can do, and what comes
across from GitHub, is in GitHub.
Where your data lives
Section titled “Where your data lives”| Volume | Holds |
|---|---|
g1t_g1t-data |
Accounts, workspaces, issues and every other record, as SQLite files; the keys that seal stored secrets (keys.env) |
g1t_g1t-git |
Your repositories, one bare git repository each |
g1t_g1t-secrets |
The key the site and the git store share |
To back up, stop g1t and copy the volumes:
docker compose -f deploy/self-host/docker-compose.yml stopdocker run --rm -v g1t_g1t-data:/data -v g1t_g1t-git:/git -v "$PWD":/backup \ debian:bookworm-slim tar czf /backup/g1t-backup.tgz /data /gitdocker compose -f deploy/self-host/docker-compose.yml startKeep keys.env with the backup. Without it, saved webhook, integration and
Actions secrets cannot be opened.
Upgrade
Section titled “Upgrade”Pull the new source and rebuild. Database changes are applied on start, and changes already applied are skipped:
git pulldocker compose -f deploy/self-host/docker-compose.yml up --build -dStop and remove
Section titled “Stop and remove”docker compose -f deploy/self-host/docker-compose.yml down # keeps your datadocker compose -f deploy/self-host/docker-compose.yml down -v # deletes it