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.
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 1 | --- |
| 2 | title: Run g1t yourself | |
| 3 | description: Start the core forge on your own machine with Docker Compose. | |
| 4 | --- | |
| 5 | ||
| 6 | g1t is MIT licensed. You can run the core forge on your own machine: | |
| 7 | accounts, workspaces, repositories, git over HTTP, issues and pull | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 8 | requests, the site to browse them, and the REST API and MCP server. Your |
| 9 | repositories are plain bare git repositories on a Docker volume. | |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 10 | |
| 11 | This is an early version. It is for trying g1t out and for small teams on | |
| 12 | a private network, not yet for an installation on the open internet. | |
| 13 | ||
| 14 | ## What works and what is off | |
| 15 | ||
| 16 | | Feature | Self-hosted | | |
| 17 | | --- | --- | | |
| 18 | | Sign up, sign in, email confirmation | Works. Mail goes to the bundled Mailpit inbox. | | |
| 19 | | Workspaces, members, access tokens | Works | | |
| Merge branch 'worktree-agent-af58ac8933b0dd125' | 20 | | Repositories: create, push and clone over HTTP, browse code, commits | Works. A fresh clone's pack is kept in the bundled object store, so the next clone of the same commit is served from there. | |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 21 | | Issues, comments, labels | Works | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 22 | | Pull requests from a branch or from a fork, merged onto the default branch | Works, when the pull request is up to date with the default branch. Bringing one up to date first needs g1t's agent, which is off. | |
| 23 | | The merge queue | Takes pull requests and shows them waiting. Testing and landing them needs g1t's agent, which is off: take a pull request out of the queue, or turn the queue off, to merge it. | | |
| 24 | | [The REST API](/reference/api/), OAuth and [MCP](/reference/mcp/) | Work, on a port of their own: `http://localhost:8789`, with the MCP server at `http://localhost:8789/mcp` | | |
| Merge branch 'worktree-agent-af58ac8933b0dd125' | 25 | | [Container images](/guides/containers/): `docker login`, push and pull at your `PUBLIC_URL` | Works, kept in the bundled object store, with no limit on a layer's size or on pulls | |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 26 | | Site search | Works | |
| status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas | 27 | | A status page of your own | Works, at `http://localhost:8788` ([below](#the-status-page)) | |
| Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member | 28 | | Webhooks, integrations | Work, retries included | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 29 | | Sign in with GitHub, import from GitHub | Off until you register a GitHub App of your own ([below](#sign-in-with-github-and-import-from-github)). Mirrors sync on GitHub's webhook once GitHub can reach your API, and with **Sync now** either way. | |
| g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent | 30 | | g1t's agent: changes, plans and reviews | Off | |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 31 | | Context hub search | Off | |
| 32 | | Deployments on `g1t.page` | Off | | |
| 33 | | Billing | Off. Nothing is charged, and no usage limit stops work. | | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 34 | | Git over SSH and the `g1t` CLI | Not available yet | |
| 35 | | Scheduled jobs | Run on their schedules inside the g1t container: webhook retries, purging deleted repositories, the packages sweep, security sweeps, audit log retention and access request summaries. Actions schedules (`on: schedule`) are not run. | | |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 36 | |
| What g1t can't do yet, and an open letter to Cloudflare | 37 | What hosted g1t cannot do yet either is on |
| 38 | [What g1t can't do yet](/about/limitations/). | |
| 39 | ||
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 40 | ## Before you start |
| 41 | ||
| 42 | - Docker with Compose v2 (`docker compose version`). | |
| 43 | - About 4 GB of free disk space for the images. | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 44 | - Ports 8787, 8788, 8789 and 8025 free on your machine. |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 45 | |
| 46 | ## Start g1t | |
| 47 | ||
| 48 | 1. Get the source: | |
| 49 | ||
| 50 | ```sh | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 51 | git clone https://g1t.sh/flagon-io/g1t.git |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 52 | cd g1t |
| 53 | ``` | |
| 54 | ||
| 55 | 2. Build and start it. The first build compiles every service and takes a | |
| 56 | while: | |
| 57 | ||
| 58 | ```sh | |
| 59 | docker compose -f deploy/self-host/docker-compose.yml up --build -d | |
| 60 | ``` | |
| 61 | ||
| 62 | 3. Open [http://localhost:8787](http://localhost:8787) and create an | |
| 63 | account. | |
| 64 | 4. Open the Mailpit inbox at [http://localhost:8025](http://localhost:8025) | |
| Merge email confirmation gate: a code and a link, nothing until confirmed (identity 0036) | 65 | and enter the code from the confirmation email on the page the site |
| 66 | shows you, or follow the link in the same email. Set `IDENTITY_KEY` | |
| 67 | (the setup does) so codes are kept as keyed hashes. | |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 68 | 5. Create a workspace, then a repository. |
| 69 | ||
| 70 | ## Push and clone | |
| 71 | ||
| 72 | The remote is the site's address, then the workspace and repository: | |
| 73 | ||
| 74 | ```sh | |
| 75 | git remote add origin http://localhost:8787/<workspace>/<repo>.git | |
| 76 | git push -u origin main | |
| 77 | ``` | |
| 78 | ||
| 79 | Git asks for a username and password: use your g1t username and password, | |
| 80 | or an access token, as described in [Git](/guides/git/#authentication). | |
| 81 | Public repositories clone without signing in: | |
| 82 | ||
| 83 | ```sh | |
| 84 | git clone http://localhost:8787/<workspace>/<repo>.git | |
| 85 | ``` | |
| 86 | ||
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 87 | ## Use the API and MCP |
| 88 | ||
| 89 | The API answers at `http://localhost:8789`, the same routes as | |
| 90 | `https://api.g1t.sh` (see the [API reference](/reference/api/)). Make an | |
| 91 | access token under **Settings → Access tokens**, then: | |
| 92 | ||
| 93 | ```sh | |
| 94 | curl -H "Authorization: Bearer $G1T_TOKEN" http://localhost:8789/user | |
| 95 | ``` | |
| 96 | ||
| 97 | The MCP server is at `http://localhost:8789/mcp`. Connect an agent to it | |
| 98 | as [Bring your own agent](/guides/bring-your-own-agent/) shows, with this | |
| 99 | address in place of `https://mcp.g1t.sh`: | |
| 100 | ||
| 101 | ```sh | |
| 102 | claude mcp add --transport http g1t http://localhost:8789/mcp | |
| 103 | ``` | |
| 104 | ||
| 105 | Applications that sign people in with OAuth find everything at | |
| 106 | `http://localhost:8789/.well-known/oauth-authorization-server`: the issuer | |
| 107 | is the API's address, and people approve on your site, at | |
| 108 | `PUBLIC_URL/oauth/authorize`. The site's clone box, agent setup and | |
| 109 | access token examples show your own addresses. | |
| 110 | ||
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 111 | ## Check an installation |
| 112 | ||
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 113 | `deploy/self-host/smoke.sh` checks an installation from end to end: |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 114 | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 115 | 1. It signs up a new account, confirms it through Mailpit, makes a |
| 116 | workspace and a repository, pushes and clones (twice, the second from | |
| 117 | the clone pack cache), opens an issue and reads the code back through | |
| 118 | the site. | |
| 119 | 2. It makes an access token and calls the API, the OAuth metadata and the | |
| 120 | MCP server with it. | |
| Merge branch 'worktree-agent-af58ac8933b0dd125' | 121 | 3. It publishes an npm package to your installation's registry and |
| 122 | installs it back. | |
| 123 | 4. It opens a pull request from a branch and one from a fork, through the | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 124 | API, and merges both onto `main`. |
| Merge branch 'worktree-agent-af58ac8933b0dd125' | 125 | 5. It turns the merge queue on, merges a pull request into it, takes it |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 126 | out again, and merges it with the queue off. |
| 127 | ||
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 128 | ```sh |
| 129 | bash deploy/self-host/smoke.sh | |
| 130 | ``` | |
| 131 | ||
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 132 | To also run every scheduled job once, give it the command that does so |
| 133 | inside the container: | |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 134 | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 135 | ```sh |
| 136 | SCHEDULER_ONCE="docker compose -f deploy/self-host/docker-compose.yml exec -T g1t \ | |
| 137 | node deploy/self-host/scheduler.mjs --once /data/generated/schedules.json" \ | |
| 138 | bash deploy/self-host/smoke.sh | |
| 139 | ``` | |
| 140 | ||
| 141 | It prints `All checks passed` when every step worked. It needs `curl`, | |
| Merge branch 'worktree-agent-af58ac8933b0dd125' | 142 | `git`, `node` and `npm`; `PACKAGES=off` skips the npm package. |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 143 | |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 144 | ## Settings |
| 145 | ||
| 146 | Set these in the environment, or in a `.env` file next to | |
| 147 | `docker-compose.yml`: | |
| 148 | ||
| 149 | | Variable | Default | What it does | | |
| 150 | | --- | --- | --- | | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 151 | | `PUBLIC_URL` | `http://localhost:8787` | The address people use. Links in email, clone addresses and the site's link previews point here. | |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 152 | | `G1T_PORT` | `8787` | The port the site is published on | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 153 | | `API_PORT` | `8789` | The port the API and the MCP server are published on | |
| 154 | | `API_URL` | `PUBLIC_URL`'s host on `API_PORT` | The address of the API, as people and applications reach it. It is also the OAuth issuer. Set it when the API is behind a proxy, for example `https://api.git.example.com`. | | |
| 155 | | `MCP_URL` | `API_URL/mcp` | The address of the MCP server. | | |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 156 | | `MAILPIT_PORT` | `8025` | The port of the Mailpit inbox | |
| 157 | | `MAIL_FROM` | `g1t <noreply@localhost>` | The sender of g1t's email | | |
| 158 | | `MAIL_URL` | `http://mailpit:8025` | The Mailpit server g1t sends mail through | | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 159 | | `REGISTRATION_MODE` | `open` | `open`: anyone can make an account. `invite`: every new account needs an [invite](/guides/authentication/#invites), as on g1t.sh. | |
| 160 | | `INVITES_PER_USER` | `5` | How many invites each person can have out, while `REGISTRATION_MODE` is `invite` | | |
| status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas | 161 | | `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. | |
| Merge branch 'worktree-agent-af58ac8933b0dd125' | 162 | | `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. | |
| Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member | 163 | | `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. | |
| Merge branch 'worktree-agent-af58ac8933b0dd125' | 164 | | `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. | |
| 165 | | `RUSTFS_IMAGE` | `rustfs/rustfs:1.0.1` | The image the bundled object store runs: [RustFS](https://rustfs.com), an S3-compatible server. | | |
| 166 | | `AWS_CLI_IMAGE` | `amazon/aws-cli:2.37.10` | The image `storage-setup` makes the buckets and the packs' lifecycle rule with. | | |
| Merge branch 'worktree-agent-ac5b181a013e54348' | 167 | | `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. | |
| status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas | 168 | | `STATUS_PORT` | `8788` | The port the status page is published on | |
| 169 | | `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-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 170 | | `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. | |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 171 | |
| status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas | 172 | ## The status page |
| 173 | ||
| 174 | The `status` service runs the same status page as | |
| 175 | [status.g1t.sh](/guides/status/), in a process of its own, so it keeps | |
| 176 | answering when the site does not. Open | |
| 177 | [http://localhost:8788](http://localhost:8788). | |
| 178 | ||
| 179 | Every minute it loads the site's sign-in page from inside Compose, and, | |
| 180 | with `STATUS_PROBE_REPO` set, lists that repository's branches. It keeps | |
| 181 | 90 days of history on its own volume, `g1t-status`. Parts an installation | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 182 | of your own does not check (the API, MCP, docs, deployments, the model |
| status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas | 183 | proxy and billing) are left off its page. |
| 184 | ||
| 185 | The links to **Status** in the site's footer and account menu still point | |
| 186 | to status.g1t.sh; pointing them at your own status page is not a setting | |
| 187 | yet. | |
| 188 | ||
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 189 | To deliver email to real inboxes, have Mailpit relay it through your SMTP |
| 190 | server. The settings are in `docker-compose.yml`, under `mailpit`. | |
| 191 | ||
| 192 | Sign-in cookies are marked `Secure`. Browsers accept them on | |
| 193 | `http://localhost`. On any other address, put g1t behind HTTPS (a reverse | |
| 194 | proxy such as Caddy or nginx with a certificate) and set `PUBLIC_URL` to | |
| 195 | the `https://` address. | |
| 196 | ||
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 197 | ## Sign in with GitHub and import from GitHub |
| 198 | ||
| 199 | g1t.sh's GitHub App works only for g1t.sh. To offer **Continue with | |
| 200 | GitHub** and **Import from GitHub** on your own g1t, register an app of | |
| 201 | your own. Without one, neither button appears. | |
| 202 | ||
| 203 | 1. On GitHub, open **Settings → Developer settings → GitHub Apps → New | |
| 204 | GitHub App** (or the same under an organization's settings). | |
| 205 | 2. Fill it in, with `PUBLIC_URL` standing for your g1t's address: | |
| 206 | ||
| 207 | | Setting | Value | | |
| 208 | | --- | --- | | |
| 209 | | Callback URL | `PUBLIC_URL/auth/github/callback` | | |
| 210 | | Expire user authorization tokens | On | | |
| 211 | | Request user authorization (OAuth) during installation | Off | | |
| 212 | | Enable Device Flow | Off | | |
| 213 | | Setup URL | `PUBLIC_URL/integrations/github/setup` | | |
| 214 | | Redirect on update | On | | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 215 | | Webhook | On, with the URL `API_URL/hooks/github` and a secret you choose, once GitHub can reach your API. Otherwise off: mirrors then sync with **Sync now**. | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 216 | | Repository permissions | Contents: Read and write; Metadata: Read; Issues: Read | |
| 217 | | Account permissions | Email addresses: Read | | |
| 218 | ||
| 219 | 3. Create it, then on its page note the **App ID**, the **Client ID** and | |
| 220 | the slug (the last part of its public address, | |
| 221 | `github.com/apps/<slug>`). Generate a **client secret** and a **private | |
| 222 | key**, which downloads a `.pem` file. | |
| 223 | 4. Set these before starting g1t, in the environment or in `.env`: | |
| 224 | ||
| 225 | | Variable | Value | | |
| 226 | | --- | --- | | |
| 227 | | `GITHUB_APP_ID` | The App ID | | |
| 228 | | `GITHUB_APP_SLUG` | The slug | | |
| 229 | | `GITHUB_APP_CLIENT_ID` | The Client ID | | |
| 230 | | `GITHUB_APP_CLIENT_SECRET` | The client secret | | |
| Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily | 231 | | `GITHUB_APP_PRIVATE_KEY` | The `.pem` file's contents, as downloaded. Line breaks may be written as `\n`. | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 232 | | `GITHUB_APP_WEBHOOK_SECRET` | The webhook secret, if the webhook is on | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 233 | |
| 234 | 5. Restart g1t: `docker compose -f deploy/self-host/docker-compose.yml up -d`. | |
| 235 | ||
| 236 | g1t makes its own key for the GitHub tokens it keeps (`IDENTITY_KEY`, in | |
| 237 | the `g1t-data` volume) on first start. What the app can do, and what comes | |
| 238 | across from GitHub, is in [GitHub](/guides/github/). | |
| 239 | ||
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 240 | ## Where your data lives |
| 241 | ||
| 242 | | Volume | Holds | | |
| 243 | | --- | --- | | |
| 244 | | `g1t_g1t-data` | Accounts, workspaces, issues and every other record, as SQLite files; the keys that seal stored secrets (`keys.env`) | | |
| 245 | | `g1t_g1t-git` | Your repositories, one bare git repository each | | |
| Merge branch 'worktree-agent-af58ac8933b0dd125' | 246 | | `g1t_g1t-objects` | The bundled object store (RustFS): container images' layers and other package files in `g1t-packages`, the `g1t-backups` bucket and the clone packs in `g1t-git-packs` | |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 247 | | `g1t_g1t-secrets` | The key the site and the git store share | |
| 248 | ||
| 249 | To back up, stop g1t and copy the volumes: | |
| 250 | ||
| 251 | ```sh | |
| 252 | docker compose -f deploy/self-host/docker-compose.yml stop | |
| 253 | docker run --rm -v g1t_g1t-data:/data -v g1t_g1t-git:/git -v "$PWD":/backup \ | |
| 254 | debian:bookworm-slim tar czf /backup/g1t-backup.tgz /data /git | |
| 255 | docker compose -f deploy/self-host/docker-compose.yml start | |
| 256 | ``` | |
| 257 | ||
| 258 | Keep `keys.env` with the backup. Without it, saved webhook, integration and | |
| 259 | Actions secrets cannot be opened. | |
| 260 | ||
| 261 | ## Upgrade | |
| 262 | ||
| 263 | Pull the new source and rebuild. Database changes are applied on start, | |
| 264 | and changes already applied are skipped: | |
| 265 | ||
| 266 | ```sh | |
| 267 | git pull | |
| 268 | docker compose -f deploy/self-host/docker-compose.yml up --build -d | |
| 269 | ``` | |
| 270 | ||
| Merge branch 'worktree-agent-af58ac8933b0dd125' | 271 | ### Installations started before 7 October 2026 |
| 272 | ||
| 273 | These kept packages' files and backups in MinIO, in the `g1t_g1t-packages` | |
| 274 | volume. The bundled store is now RustFS, in `g1t_g1t-objects`, and starts | |
| 275 | empty. After the upgrade above, copy the old objects across (use your own | |
| 276 | `S3_ACCESS_KEY_ID` and `S3_SECRET_ACCESS_KEY` if you changed them): | |
| 277 | ||
| 278 | ```sh | |
| 279 | docker run -d --name g1t-old-store --network g1t_default \ | |
| 280 | -v g1t_g1t-packages:/data -e MINIO_ROOT_USER=g1t \ | |
| 281 | -e MINIO_ROOT_PASSWORD=g1t-packages-secret pgsty/minio server /data | |
| 282 | docker run --rm --network g1t_default -e AWS_ACCESS_KEY_ID=g1t \ | |
| 283 | -e AWS_SECRET_ACCESS_KEY=g1t-packages-secret -e AWS_DEFAULT_REGION=us-east-1 \ | |
| 284 | --entrypoint sh amazon/aws-cli:2.37.10 -c ' | |
| 285 | for b in g1t-packages g1t-backups; do | |
| 286 | aws --endpoint-url http://g1t-old-store:9000 s3 sync "s3://$b" "/tmp/$b" && | |
| 287 | aws --endpoint-url http://rustfs:9000 s3 sync "/tmp/$b" "s3://$b" | |
| 288 | done' | |
| 289 | docker rm -f g1t-old-store | |
| 290 | ``` | |
| 291 | ||
| 292 | The clone packs are not copied: they are a cache, and are made again on | |
| 293 | the next clone. Once your images and packages pull, remove the old volume | |
| 294 | with `docker volume rm g1t_g1t-packages`. | |
| 295 | ||
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 296 | ## Stop and remove |
| 297 | ||
| 298 | ```sh | |
| 299 | docker compose -f deploy/self-host/docker-compose.yml down # keeps your data | |
| 300 | docker compose -f deploy/self-host/docker-compose.yml down -v # deletes it | |
| 301 | ``` |
This file's history is long; its oldest lines are credited to the oldest commit read.