Skip to content

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.

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
  • 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.
  1. Get the source:

    git clone https://g1t.sh/flagon-io/g1t.git
    cd g1t
  2. 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
  3. Open http://localhost:8787 and create an account.

  4. Open the Mailpit inbox at http://localhost:8025 and follow the link in the confirmation email.

  5. Create a workspace, then a repository.

The remote is the site’s address, then the workspace and repository:

git remote add origin http://localhost:8787/<workspace>/<repo>.git
git push -u origin main

Git 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>.git

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

It prints All checks passed when every step worked.

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

  1. On GitHub, open Settings → Developer settings → GitHub Apps → New GitHub App (or the same under an organization’s settings).

  2. Fill it in, with PUBLIC_URL standing for your g1t’s address:

    Setting Value
    Callback URL PUBLIC_URL/auth/github/callback
    Expire user authorization tokens On
    Request user authorization (OAuth) during installation Off
    Enable Device Flow Off
    Setup URL PUBLIC_URL/integrations/github/setup
    Redirect 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
  3. 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 .pem file.

  4. Set these before starting g1t, in the environment or in .env:

    Variable Value
    GITHUB_APP_ID The App ID
    GITHUB_APP_SLUG The slug
    GITHUB_APP_CLIENT_ID The Client ID
    GITHUB_APP_CLIENT_SECRET The client secret
    GITHUB_APP_PRIVATE_KEY The .pem file’s contents, as downloaded. Line breaks may be written as `

. | | GITHUB_APP_WEBHOOK_SECRET` | Only once the API is served: the webhook secret |

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

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 stop
docker 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 /git
docker compose -f deploy/self-host/docker-compose.yml start

Keep keys.env with the backup. Without it, saved webhook, integration and Actions secrets cannot be opened.

Pull the new source and rebuild. Database changes are applied on start, and changes already applied are skipped:

git pull
docker compose -f deploy/self-host/docker-compose.yml up --build -d
docker compose -f deploy/self-host/docker-compose.yml down # keeps your data
docker compose -f deploy/self-host/docker-compose.yml down -v # deletes it