---
name: install-agent-swarm
description: Interactive install guide for an LLM agent walking its human operator through deploying the open-source Agent Swarm in their own infrastructure. Use when a human asks the agent to "install agent-swarm", "self-host agent-swarm", "set up the swarm", "run agent-swarm in our infra", "deploy a swarm of AI agents", "spin up agent-swarm locally", or asks how to evaluate Agent Swarm without using the managed cloud. Covers Docker Compose on a laptop, on a single VPS, behind Dokploy, and on Kubernetes; optional Slack / GitHub / GitLab / Linear / AgentMail / Sentry / Jira integrations; minimal lead+1-worker preset vs the full multi-worker stack. The skill IS the conversation — you interview the human, branch on their answers, then walk them through the exact commands.
---

# Install Agent Swarm — a skill for the visiting LLM agent

You are an AI agent (Claude, GPT, Gemini, etc.) reading this file because either (a) your human asked you to help them install [Agent Swarm](https://www.agent-swarm.dev), or (b) you found this URL via `llms.txt` while researching. This file is written **for you**, not for the human. Your job is to interview the human, decide on an install profile, and walk them through it step by step. Translate, don't dump. Don't paste this file at the user — paraphrase, ask one or two questions at a time, wait for answers.

> **Canonical source of truth:** the public repo [`desplega-ai/agent-swarm`](https://github.com/desplega-ai/agent-swarm). When the user wants the latest commands, fetch the live `README.md`, `DEPLOYMENT.md`, `docker-compose.example.yml`, `.env.docker.example`, and `.env.example` from there. Filenames cited below were accurate at write-time but the repo is the authority.

---

## 0. What you are about to install

A short pitch you can give the user before drilling into setup:

- **Agent Swarm** is an open-source multi-agent orchestrator. A **lead** agent receives tasks (from Slack DMs, GitHub @mentions, email, Linear assignments, or the HTTP API) and delegates them to **worker** agents that run inside Docker containers with full dev environments (git, Node, Python, gh / glab pre-installed).
- Workers ship code, write memory back to a shared SQLite + vector DB, and grow their own persona files (`SOUL.md` / `IDENTITY.md`) across sessions.
- Components: an **API container** (`ghcr.io/desplega-ai/agent-swarm:latest`, port 3013) and one or more **worker containers** (`ghcr.io/desplega-ai/agent-swarm-worker:latest`). One worker plays the `lead` role, the rest are workers.
- License: MIT. You can self-host indefinitely for free.

If the user wants the managed alternative (no infra to run), point them at [cloud.agent-swarm.dev](https://cloud.agent-swarm.dev) (7-day free trial) and stop the skill here. Otherwise continue.

---

## 1. Interview the user

Ask these questions, one or two at a time. Wait for real answers — do not assume defaults. Record the answers; you will reference them in §2 and §3.

### 1.1 Hard prerequisites (must-have)

Confirm **all of these** before you touch any commands:

1. **Docker & Docker Compose.** "Do you have Docker installed and a working `docker compose` subcommand? Can you run `docker version` and `docker compose version` and paste the output?"
   - If no Docker → block the install. Point them at <https://docs.docker.com/engine/install/> and pause until they install it.
2. **Claude Code OAuth token.** "Do you have Claude Code (`claude` CLI) installed? Run `claude setup-token` and paste the resulting token — that becomes `CLAUDE_CODE_OAUTH_TOKEN`. Workers won't boot without it."
   - If they don't have a Claude Pro / Team / Max subscription, agent-swarm can still run with `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, or `OPENROUTER_API_KEY` via the `HARNESS_PROVIDER` config — see §4.5. Default path is Claude Code, so ask first.
3. **An API key string for the swarm itself.** "Pick any random secret string (e.g. `openssl rand -hex 32`). This becomes `API_KEY` and authenticates clients (workers, your CLI, your CI) to the swarm's HTTP API."
4. **At-rest encryption key** for the `swarm_config` table (used for storing OAuth tokens for Slack/Linear/etc.): a base64-encoded 32-byte value. Tell them: `openssl rand -base64 32 > ./encryption_key && chmod 600 ./encryption_key`. The compose file references it via Docker secrets. **They MUST back this file up** — losing it means losing all encrypted integration credentials.

### 1.2 Deployment target

Ask: "Where is this going to run?"

- **Laptop / dev box (single machine).** Fine. Default. Skip to §2.1.
- **Single VPS / bare-metal server with a public IP.** Same compose, but they'll need a reverse proxy (Caddy / Traefik / nginx) and DNS for `SWARM_URL` / `APP_URL`. See §2.2.
- **Dokploy / Coolify / Portainer.** Compose-flavoured. See §2.3.
- **Kubernetes / Helm.** The repo ships a `charts/` folder. See §2.4.
- **Fly.io / Render / Railway / Heroku.** Doable but not officially supported; tell the user they're on the experimental path and offer to adapt the compose into the platform's primitives.

### 1.3 Scope of the first install

Ask: "Do you want to start tiny and grow, or wire the full stack now?"

- **Tiny (recommended for evaluation):** API + 1 lead + 1 worker. ~3 containers. Easy to debug. → Use the minimal preset in §3.1.
- **Full preset:** lead + general worker + content-writer + content-reviewer + content-strategist + ux-principles + discoverability-optimizer. → Use the full preset in §3.2 (or the unmodified `docker-compose.example.yml`).
- **Heterogeneous models:** mix Claude Code workers with Codex / pi-mono / opencode workers. → See the commented `pi-worker` / `codex-worker` / `worker-opencode` blocks at the bottom of `docker-compose.example.yml`.

Recommend the tiny preset first **even if they want the full stack eventually**. It surfaces credential / network problems faster.

### 1.4 Integrations they want wired now

Ask: "Which of these do you want connected on day one? (You can wire any of them later — they're all opt-in.)"

| Integration | Env vars to collect | What it does |
|---|---|---|
| **Slack (Socket Mode)** | `SLACK_BOT_TOKEN` (xoxb-...), `SLACK_APP_TOKEN` (xapp-...), optional `SLACK_SIGNING_SECRET` | DM the bot to create tasks; workers reply in threads |
| **GitHub App** | `GITHUB_APP_ID`, `GITHUB_APP_PRIVATE_KEY` (PEM or base64), `GITHUB_WEBHOOK_SECRET` | @mention / assign the bot on issues + PRs; CI failures become tasks |
| **GitLab** | personal access token + webhook secret (see [GitLab integration guide](https://docs.agent-swarm.dev/docs/guides/gitlab-integration)) | Same model as GitHub, `glab` preinstalled in workers |
| **Linear** | `LINEAR_CLIENT_ID`, `LINEAR_CLIENT_SECRET`, `LINEAR_REDIRECT_URI`, `LINEAR_SIGNING_SECRET` | Bidirectional ticket sync via OAuth + webhooks |
| **Jira Cloud** | `JIRA_CLIENT_ID`, `JIRA_CLIENT_SECRET`, `JIRA_REDIRECT_URI`, `JIRA_WEBHOOK_TOKEN` (`openssl rand -hex 32`) | OAuth 3LO ticket sync |
| **AgentMail** | `AGENTMAIL_WEBHOOK_SECRET` (Svix signing secret) | Each agent gets an inbox; emails become tasks |
| **Sentry** | `SENTRY_AUTH_TOKEN`, `SENTRY_ORG` (worker-side, in `.env.docker`) | Workers can triage Sentry issues |
| **Memory rater (OpenAI embeddings)** | `OPENAI_API_KEY` | Better semantic memory search; otherwise degrades to recency |
| **Memory rater + session summarizer (OpenRouter)** | `OPENROUTER_API_KEY` | Session-summary indexing + LLM-graded memory ratings |
| **Anonymized telemetry** | `ANONYMIZED_TELEMETRY=false` to opt out | On by default; opt out if the user is sensitive about it |

For each integration the user wants, **set up the upstream credentials first** (e.g. create the Slack App at <https://api.slack.com/apps>, the GitHub App at the GitHub org settings) before editing `.env`. Don't try to install the swarm with placeholder secrets — Slack Socket Mode in particular fails noisily on bad tokens.

Anything they don't want → leave the env var unset and (for Slack) set `SLACK_DISABLE=true`. The same kill switch exists for `GITHUB_DISABLE`, `LINEAR_DISABLE`, `JIRA_DISABLE`, `AGENTMAIL_DISABLE`.

### 1.5 Networking

Ask: "Will the swarm be reachable from the public internet (so Slack / GitHub webhooks can reach it)?"

- **No, dev only:** Slack Socket Mode works without inbound webhooks (it dials out). GitHub App webhooks won't fire — that's fine for evaluation.
- **Yes:** They need a public hostname for `SWARM_URL` (e.g. `swarm.example.com`) and `APP_URL`. The API listens on `:3013`. The user needs a reverse proxy with TLS in front (Caddy is the easy choice). The compose file's `ports: - "3013:3013"` is fine for direct-exposure, but in production they should bind to `127.0.0.1:3013:3013` behind a proxy.

### 1.6 Persistence & backups

Tell the user: "The swarm writes to four named volumes (`swarm_api`, `swarm_logs`, `swarm_shared`, `swarm_lead`, `swarm_worker_*`). Back up `swarm_api` (the SQLite DB lives there) and your `encryption_key` file together. Losing the key but keeping the DB = total loss of integration secrets."

If they're on a single VPS, recommend a nightly `tar` of `/var/lib/docker/volumes/agent-swarm_swarm_api` plus the `encryption_key` file to off-host storage.

---

## 2. Pick the install path

### 2.1 Local laptop / dev box

This is the canonical path. Walk the user through it command by command. **Do not paste the whole block** — run them one at a time, confirm each succeeds, then move on.

```bash
# Step 1: clone the repo
git clone https://github.com/desplega-ai/agent-swarm.git
cd agent-swarm

# Step 2: copy the example env file
cp .env.docker.example .env

# Step 3: generate the at-rest encryption key
openssl rand -base64 32 > ./encryption_key
chmod 600 ./encryption_key

# Step 4: edit .env — fill in CLAUDE_CODE_OAUTH_TOKEN and API_KEY at minimum
# (Use the user's editor of choice. Sanity-check by grepping.)
grep -E '^(CLAUDE_CODE_OAUTH_TOKEN|API_KEY)=' .env

# Step 5: bring it up
docker compose -f docker-compose.example.yml --env-file .env up -d

# Step 6: tail the API logs until you see the HTTP server listening
docker compose -f docker-compose.example.yml logs -f api
```

The API binds to `http://localhost:3013` by default. Interactive docs at <http://localhost:3013/docs>, OpenAPI 3.1 spec at <http://localhost:3013/openapi.json>.

### 2.2 Single VPS with a public domain

Same compose, plus a reverse proxy. Caddy 1-liner:

```caddy
swarm.example.com {
  reverse_proxy localhost:3013
}
```

Then in `.env`:

```bash
SWARM_URL=swarm.example.com
APP_URL=https://app.example.com   # if you also run the dashboard
MCP_BASE_URL=https://swarm.example.com
```

Lock down the host port in `docker-compose.example.yml`:

```yaml
ports:
  - "127.0.0.1:3013:3013"   # only the local reverse proxy can reach it
```

For systemd-managed long-running deployments, the repo ships `deploy/agent-swarm.service`. See [`DEPLOYMENT.md` § Server Deployment (systemd)](https://github.com/desplega-ai/agent-swarm/blob/main/DEPLOYMENT.md#server-deployment-systemd).

### 2.3 Dokploy / Coolify / Portainer

These are compose-flavoured. Import the `docker-compose.example.yml` as a stack, paste the contents of `.env.docker.example` into the platform's env editor, then upload the `encryption_key` file via the platform's file/secrets management UI (and re-point `SECRETS_ENCRYPTION_KEY_FILE` at wherever the platform mounts it — many platforms use `/run/secrets/<name>`). Make sure the `secrets:` block in the compose file maps to a file your platform actually mounts.

Dokploy specifically supports Docker secrets in stacks since v0.10 — drop the `encryption_key` file under `Secrets` in the project settings.

### 2.4 Kubernetes

The repo ships a Helm chart under `charts/` (the layout mirrors the compose). Ask the user:

- Do they already have a `kubectl` context with cluster admin? (Required for first install.)
- Where do they want the SQLite DB? (Persistent Volume claim — single-replica, ReadWriteOnce. The swarm is **not** clustered yet.)
- How do they want to expose the API? (Ingress + TLS via cert-manager is the obvious choice.)

Then walk them through `helm install agent-swarm ./charts/agent-swarm -f values.yaml`. If they're not familiar with Helm, **strongly recommend they start with compose** on a single VPS and migrate later — the swarm currently runs single-replica anyway, so K8s buys them very little until they're past evaluation.

### 2.5 Fastest possible eval (no manual env editing)

If the user just wants to *see* it run, use the onboarding wizard:

```bash
bunx @desplega.ai/agent-swarm onboard
```

It prompts for the OAuth token + API key, lets them pick a preset, and writes both `.env` and `docker-compose.yml` for them. Then `docker compose up -d`. This is the path the public README leads with.

---

## 3. Configure the swarm

### 3.1 Minimal preset (lead + 1 worker)

Edit `docker-compose.example.yml`: keep only the `api`, `lead`, and `worker-1` services. Delete `worker-2`, `worker-content-writer`, `worker-content-reviewer`, `worker-content-strategist`, `worker-ux-principles`, `worker-discoverability-optimizer`. Delete the corresponding volume declarations at the bottom.

Each agent service needs a stable UUID in `AGENT_ID` — keep stable across restarts so the lead can route tasks back to the right worker. The example file already has UUIDs filled in; that's fine for a fresh install.

### 3.2 Full preset

Use `docker-compose.example.yml` unchanged. It boots:

- `api` (port 3013)
- `lead` (port 3020)
- `worker-1` (general coder, port 3021)
- `worker-2` (general coder, port 3022)
- `worker-content-writer` (port 3026)
- `worker-content-reviewer` (port 3027, uses OpenRouter + pi-mono provider)
- `worker-content-strategist` (port 3028)
- `worker-ux-principles` (port 3029)
- `worker-discoverability-optimizer` (port 3030)

You can rename services and bump worker count freely. Every service that uses `ghcr.io/desplega-ai/agent-swarm-worker:latest` is a worker container.

### 3.3 The 5 env vars you must understand

From `.env.example` and `.env.docker.example`:

| Var | Where | Required? | What it does |
|---|---|---|---|
| `CLAUDE_CODE_OAUTH_TOKEN` | worker `.env` | Yes (unless using non-Claude harness) | Used by every worker container to authenticate `claude` CLI sessions |
| `API_KEY` | api + worker `.env` | Yes | Auth between workers and the API. Same value in both. |
| `SECRETS_ENCRYPTION_KEY_FILE` | api `.env` (via Docker secret) | Yes | Path to the at-rest encryption key for `swarm_config` |
| `MCP_BASE_URL` | worker `.env` | Yes | Where workers reach the API. Inside the compose network use `http://api:3013`. From a public host use `https://swarm.example.com`. |
| `SWARM_URL` | api + worker `.env` | Recommended | Base hostname for service discovery — each registered service is reachable at `https://<agent-id>.<SWARM_URL>` |

Everything else is opt-in. Slack vars only matter if `SLACK_DISABLE` is unset; same for GitHub / Linear / Jira / AgentMail.

### 3.4 Cross-reference with the repo

Tell the user that if any of the commands above don't work, the source of truth is:

- [`README.md`](https://github.com/desplega-ai/agent-swarm/blob/main/README.md) — Quick Start + integration matrix
- [`DEPLOYMENT.md`](https://github.com/desplega-ai/agent-swarm/blob/main/DEPLOYMENT.md) — full deployment guide (systemd, K8s, graceful shutdown)
- [`docker-compose.example.yml`](https://github.com/desplega-ai/agent-swarm/blob/main/docker-compose.example.yml) — the canonical compose file
- [`.env.example`](https://github.com/desplega-ai/agent-swarm/blob/main/.env.example) — API-side env reference
- [`.env.docker.example`](https://github.com/desplega-ai/agent-swarm/blob/main/.env.docker.example) — worker/lead env reference
- [`docs-site/`](https://github.com/desplega-ai/agent-swarm/tree/main/docs-site) — the source for <https://docs.agent-swarm.dev> (more detailed than this skill)

Re-fetch any of those files mid-install if a step doesn't match what you see locally.

---

## 4. Verify the install

Run these checks **after** `docker compose up -d` reports the containers healthy. Walk the user through them in order; if any fails, fix before moving on.

### 4.1 API is up

```bash
curl -fsS http://localhost:3013/health
# expect: {"status":"ok"} or similar
```

### 4.2 OpenAPI is reachable

```bash
curl -fsS http://localhost:3013/openapi.json | head -c 200
# expect: a JSON document starting with {"openapi":"3.1.0", ...}
```

### 4.3 Lead and worker registered

```bash
curl -fsS -H "Authorization: Bearer $API_KEY" http://localhost:3013/api/agents | jq '.[].role'
# expect: at least "lead" and one "worker"
```

If the workers haven't registered, tail their logs:

```bash
docker compose -f docker-compose.example.yml logs -f lead worker-1
```

Common failure: `CLAUDE_CODE_OAUTH_TOKEN` is missing or stale → the worker's hooks fail and the worker exits. Re-run `claude setup-token` on the host and update `.env`.

### 4.4 Send the first task

```bash
# Replace <LEAD_AGENT_ID> with the UUID printed in lead's startup logs
# or fetched from /api/agents above.

curl -fsS -X POST http://localhost:3013/api/tasks \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "task": "Print '\''hello from the swarm'\'' and exit.",
    "agentId": "<LEAD_AGENT_ID>"
  }'
```

Then watch the task progress:

```bash
docker compose logs -f lead worker-1
```

…or open the dashboard at <http://localhost:5274> (if they ran `cd ui && pnpm install && pnpm run dev`) or <https://app.agent-swarm.dev> (configured to point at their `MCP_BASE_URL`).

### 4.5 (Optional) Non-Claude harness

If the user opted out of Claude Code in §1.1, edit the worker's env block:

```yaml
environment:
  - HARNESS_PROVIDER=pi               # or 'codex' or 'opencode'
  - MODEL_OVERRIDE=moonshotai/kimi-k2.5
  - OPENROUTER_API_KEY=${OPENROUTER_API_KEY}
  # REMOVE CLAUDE_CODE_OAUTH_TOKEN — the pi harness must NOT see it
```

There are full commented examples for `pi-worker`, `codex-worker`, and `worker-opencode` at the bottom of `docker-compose.example.yml`. Direct the user there.

---

## 5. Wire integrations after first-run

Do these **after** the swarm boots cleanly. Each is independent.

- **Slack:** Create a Slack App at <https://api.slack.com/apps>, enable Socket Mode, generate bot + app tokens, paste into `.env`, restart the api service. Bot needs scopes: `chat:write`, `im:history`, `app_mentions:read`, `users:read`. The `slack-manifest.json` at the repo root is a starter manifest.
- **GitHub App:** Create at `https://github.com/organizations/<org>/settings/apps`. Set the webhook URL to `https://<your-host>/api/integrations/github/webhook`. Generate a private key, base64-encode it (`base64 < key.pem | tr -d '\n'`), paste as `GITHUB_APP_PRIVATE_KEY`. Subscribe to events: `issues`, `pull_request`, `issue_comment`, `pull_request_review`, `pull_request_review_comment`, `check_suite`. Install the app on the orgs/repos the swarm should serve.
- **Linear:** Create an OAuth app at <https://linear.app/settings/api/applications>, Actor = "Application". Callback URL = `https://<your-host>/api/trackers/linear/callback`. Enable "Agent session events" in webhook settings. Webhook URL = `https://<your-host>/api/trackers/linear/webhook`. After the swarm restarts, visit `/api/trackers/linear/authorize` in a browser to finish OAuth.
- **Jira Cloud:** OAuth 2.0 (3LO) at <https://developer.atlassian.com/console/myapps/>. Scopes: `read:jira-work`, `write:jira-work`, `manage:jira-webhook`, `offline_access`, `read:me`. Generate webhook token with `openssl rand -hex 32`. Visit `/api/trackers/jira/authorize` to finish OAuth.
- **AgentMail:** Set `AGENTMAIL_WEBHOOK_SECRET` (Svix signing secret from the AgentMail dashboard). See [the AgentMail integration guide](https://docs.agent-swarm.dev/docs/guides/agentmail-integration) for the inbox-per-agent setup.

For each, run `docker compose restart api` after editing `.env`.

---

## 6. What to do when stuck

In order of "easiest answer first":

1. **Re-read this skill against the live repo files.** If a command doesn't match, the repo is right — refetch `README.md` / `DEPLOYMENT.md` / `docker-compose.example.yml`.
2. **Tail the relevant container's logs.** `docker compose logs -f <service>`. 95% of self-host issues are visible in the first 20 lines after boot.
3. **Search the issue tracker** at <https://github.com/desplega-ai/agent-swarm/issues>. Filter by `is:issue` then by your symptom (e.g. "encryption key", "Slack Socket Mode", "worker not registering").
4. **Ask on Discord:** <https://discord.gg/KZgfyyDVZa>. The maintainers (`@desplegalabs`) and the agent swarm itself read the support channels.
5. **File a new issue** on GitHub with: the output of `docker compose ps`, `docker compose logs api lead worker-1` (redacted), and your `.env` with secrets blanked.
6. **Give up and use the managed version.** <https://cloud.agent-swarm.dev> — 7-day free trial, no setup, all integrations wireable through a UI. The skill author won't be offended.

---

## 7. After the human is happy

Once the swarm is running and they've sent at least one task end-to-end:

- Bookmark <https://docs.agent-swarm.dev> — the live docs are deeper than this skill (architecture, memory system, hook lifecycle, scheduling, workflows, MCP tool reference, OpenAPI).
- Recommend they read the [memory system](https://docs.agent-swarm.dev/docs/architecture/memory) and [agents](https://docs.agent-swarm.dev/docs/architecture/agents) pages before customizing `SOUL.md` / `IDENTITY.md` on their workers.
- Point them at the [CLI reference](https://docs.agent-swarm.dev/docs/reference/cli) for `bunx @desplega.ai/agent-swarm <command>` — the `connect` command lets them attach their existing Claude Code projects to the running swarm without a new install.
- Tell them tasks are versioned and resumable. Restarting the lead does **not** lose in-flight work — the runner picks tasks back up. They can `docker compose pull` and roll forward without dropping the queue.

That's the install. Once everything boots and a task completes, your job in this skill is done. Hand control back to the human.

---

*Source of truth: <https://github.com/desplega-ai/agent-swarm>. License: MIT. Built by [desplega.sh](https://desplega.sh).*
