skip to content
agentmash get started
docsyour own server

run it yourself

your own server

Self-hosting is part of the enterprise plan. npx agentmash login and init use agentmash.dev unless told otherwise; your own server is one Docker image and one SQLite file: you need Docker on a machine your team can reach, and no checkout of AgentMash. On your own server, prompt excerpts never leave your network.

Getting access

The image, ghcr.io/agentmash-dev/agentmash, is a private package on GitHub's container registry, so pulling it takes a login from us.

  1. Write to hello@agentmash.dev for the enterprise plan.
  2. We send you a GitHub user name and a token for it that can only read packages (the read:packages scope).
  3. On the machine that runs it, log in to the registry as that user. When it asks for a password, give it the token:
docker login ghcr.io -u <the-user-we-send>

Docker keeps the login, so the docker run, docker pull and Compose below pull the image with it. Without it, a pull is refused.

Run it

bash
docker run -d --name agentmash --restart unless-stopped \
  -p 8787:8787 \
  -v agentmash-data:/data \
  -e AGENTMASH_PUBLIC_URL=https://agentmash.example.com \
  -e GITHUB_CLIENT_ID=... \
  -e GITHUB_CLIENT_SECRET=... \
  ghcr.io/agentmash-dev/agentmash:latest

It listens on port 8787. Everything it keeps is in /data/agentmash.db, so /data is a volume: without one, the rooms go when the container does. Once it can read the database, curl http://localhost:8787/readyz answers {"ok":true}.

The image is built for amd64 and arm64. latest is the newest build; each release also has its version as a tag, such as 0.9.0, to pin.

Settings

VariableWhat it does
AGENTMASH_PUBLIC_URLThe address your team reaches it at. It is in every link the server prints, in the config init writes and in GitHub's callback, so set it before anyone connects. Default http://localhost:8787
GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRETThe GitHub OAuth app people sign in with (below). Without them the server runs, but nobody can sign in
AGENTMASH_CLOSED1 keeps it to the GitHub logins in AGENTMASH_ALLOW: only they can sign in, and nobody makes a room without signing in. Rooms that already exist carry on. Anyone else is told it isn't taking new teams, and to write to AGENTMASH_MAIL_REPLY_TO (else the address in AGENTMASH_MAIL_FROM) when one is set
AGENTMASH_ALLOWGitHub logins, comma-separated, that can sign in while it is closed
AGENTMASH_DBThe SQLite file. Default /data/agentmash.db in the image
PORTWhere it listens. Default 8787

Anyone who can reach an open server can sign in with GitHub and connect a repository, so a server on the internet wants AGENTMASH_CLOSED=1 and your team's logins in AGENTMASH_ALLOW.

The server takes no sign-ups, so it has no mail to send. RESEND_API_KEY (a Resend key) and AGENTMASH_MAIL_FROM only matter to a server that took sign-ups for agentmash's old launch list before it closed: a welcome one of those is still owed goes out with them, up to 14 days after that sign-up. AGENTMASH_MAIL_REPLY_TO is also the address a closed server tells people to write to. Leave them all unset and nothing is sent, and a closed server's refusal names no address.

Every other setting is in the configuration.

Sign-in: a GitHub OAuth app

People sign in with GitHub, on the website and with npx agentmash login, and GitHub says which repositories each of them can push to. That takes an OAuth app of your own:

  1. On GitHub, open Settings → Developer settings → OAuth Apps → New OAuth App. An organization has the same page in its own settings.
  2. Homepage URL: your AGENTMASH_PUBLIC_URL. Authorization callback URL: the same address with /auth/github/callback after it, such as https://agentmash.example.com/auth/github/callback.
  3. Register it, generate a client secret, and give the server the client ID as GITHUB_CLIENT_ID and the secret as GITHUB_CLIENT_SECRET.

If your organization restricts OAuth apps, an owner approves this one (the organization's Settings → Third-party access), or its repositories stay out of reach of the sign-in.

Docker Compose

yaml
services:
  agentmash:
    image: ghcr.io/agentmash-dev/agentmash:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:8787:8787"
    environment:
      AGENTMASH_PUBLIC_URL: https://agentmash.example.com
      AGENTMASH_CLOSED: "1"
      AGENTMASH_ALLOW: alice,bob
      GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID}
      GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET}
    volumes:
      - agentmash-data:/data

volumes:
  agentmash-data:

Put GITHUB_CLIENT_ID=... and GITHUB_CLIENT_SECRET=... in a .env file beside it, where Compose reads them, and run docker compose up -d. The port is bound to 127.0.0.1, for a proxy on the same machine to put HTTPS in front.

HTTPS

Every credential here is a bearer token, so put HTTPS in front before anyone connects: over plain HTTP, anyone on the network can read a room key off the wire. Any reverse proxy does, as long as it passes WebSocket upgrades through, which the live view uses. With Caddy, which gets the certificate itself, this is the whole Caddyfile:

caddyfile
agentmash.example.com {
    reverse_proxy localhost:8787
}

Set AGENTMASH_PUBLIC_URL to the https:// address: the sign-in's cookies are marked Secure only then.

Pointing the CLI at it

Each developer signs in to your server instead of agentmash.dev:

npx agentmash login --server https://agentmash.example.com

A machine is signed in to one server at a time; login --server again moves it. A repository is connected once, by someone who can push to it, at your server's /install, such as https://agentmash.example.com/install. npx agentmash init --server https://agentmash.example.com commits a room to a repository instead, but only on an open server: with AGENTMASH_CLOSED=1 it is refused for everyone, the logins in AGENTMASH_ALLOW too, so a closed server's repositories are connected at /install. The rest of the setup is the same on your server as on agentmash.dev.

Upgrading

bash
docker pull ghcr.io/agentmash-dev/agentmash:latest
docker stop agentmash && docker rm agentmash

Then the same docker run as before. With Compose, docker compose pull and docker compose up -d. The server updates its tables itself when it starts, so take a backup first. The rooms, keys and sign-ins are in the volume and carry over. If a pull is refused, run the docker login above again with a new token from us.

Backups

Everything is in the one SQLite file. The server writes it in WAL mode, so a copy of agentmash.db taken while it runs can miss the newest writes. Ask SQLite for a copy instead, from inside the container:

bash
docker exec agentmash node -e "require('better-sqlite3')('/data/agentmash.db').backup('/data/backup.db').then(() => console.log('done'))"
docker cp agentmash:/data/backup.db ./agentmash-backup.db

With Compose, docker compose exec and docker compose cp do the same. To restore, stop the server, put the copy back as agentmash.db with no agentmash.db-wal or agentmash.db-shm left beside it, and start it again:

bash
docker stop agentmash
docker run --rm -v agentmash-data:/data -v "$PWD":/backup ghcr.io/agentmash-dev/agentmash:latest \
  sh -c "cp /backup/agentmash-backup.db /data/agentmash.db && rm -f /data/agentmash.db-wal /data/agentmash.db-shm"
docker start agentmash

from docs/SELF-HOST.md, “Running AgentMash on your own server”