# Running with Docker

Squadron publishes Docker images to GitHub Container Registry on every release. Two variants are available:

| Image | Tag | Use case |
|-------|-----|----------|
| Alpine | `ghcr.io/mlund01/squadron:latest` | Default — small, static binary |
| Debian | `ghcr.io/mlund01/squadron:latest-debian` | Plugins that need glibc/CGO |

Both images support `linux/amd64` and `linux/arm64`.

## Quick Start

```bash
docker run --rm ghcr.io/mlund01/squadron version
```

## Mounts

Squadron in Docker uses a single mount point:

| Mount | Purpose |
|-------|---------|
| `/config` | Your HCL configuration files and `.squadron/` state directory |

All runtime state (vault, plugins, database) lives in `/config/.squadron/`, right alongside your HCL config files. The container's working directory is `/config`, so the `-c` flag is not needed.

## Run with the Command Center UI

```bash
docker run -it \
  -v ./my-project:/config \
  -p 8080:8080 \
  ghcr.io/mlund01/squadron engage
```

- `-it` is optional — with it, the quickstart wizard runs on an empty project. Without it, Squadron auto-initializes and you set everything up from the UI.
- `-p 8080:8080` publishes the command center to the host. Open `http://localhost:8080`.

The official image sets `SQUADRON_CONTAINER=1`, which makes Squadron run in the foreground and skip browser auto-open. You never need to pass `--foreground` here. Pass `--headless` if you want Squadron to run without the UI (for example, when missions run purely via schedules or a remote command center).

If some variables are missing, Squadron still starts — the UI lets you set them after the container is up.

## Connect to a Remote Command Center

If your HCL config declares a `command_center` block, Squadron connects outbound — no port mapping needed:

```bash
docker run \
  -v ./my-project:/config \
  ghcr.io/mlund01/squadron engage
```

The local UI is skipped automatically when a `command_center` block is present.

## Run a Single Mission

```bash
docker run \
  -v ./my-project:/config \
  ghcr.io/mlund01/squadron mission --init my_mission
```

## Docker Compose

```yaml
services:
  squadron:
    image: ghcr.io/mlund01/squadron:latest
    volumes:
      - ./my-project:/config
    command: ["engage"]
    ports:
      - "8080:8080"
```

```bash
docker compose up
```

## Setting Variables

Variables are stored in an encrypted vault at `/config/.squadron/vars.vault`. There are two ways to set them:

**Via the command center UI** (easiest): Open the UI at `http://localhost:8080`, navigate to Variables, and add them there.

**Via `vars set` in a running container**:

```bash
docker exec <container> squadron vars set anthropic_api_key sk-ant-...
```

## Securing the Vault Passphrase

By default, when Squadron auto-initializes the vault, it writes the passphrase to `/config/.squadron/vault.key` with `0600` permissions. This works fine when the volume is local and trusted.

For stronger production setups, mount a passphrase file as a Docker secret:

```yaml
services:
  squadron:
    image: ghcr.io/mlund01/squadron:latest
    volumes:
      - ./my-project:/config
    command: ["engage"]
    secrets:
      - vault_passphrase
    ports:
      - "8080:8080"

secrets:
  vault_passphrase:
    file: ./vault_passphrase.txt
```

Squadron checks `/run/secrets/vault_passphrase` automatically. If the file exists, it uses that passphrase instead of the on-disk key. Docker mounts secrets as tmpfs, so the passphrase never touches the container's disk.

## Pinning a Version

Use a version tag instead of `latest`:

```bash
docker pull ghcr.io/mlund01/squadron:v0.0.45
docker pull ghcr.io/mlund01/squadron:v0.0.45-debian
```

## Alpine vs Debian

- **Alpine** (`latest`) — smaller image, static binary with `CGO_ENABLED=0`. Use this unless you have a reason not to.
- **Debian** (`latest-debian`) — larger image, built with `CGO_ENABLED=1`. Use this if you have plugins that depend on C libraries or glibc.

Both images ship with the toolchains needed to build local plugins at config-load time:

- **Python plugins** (`pyproject.toml` source) — `python3` + `pip` are pre-installed; Squadron creates an isolated venv per plugin under `/config/.squadron/plugins/`.
- **Go plugins** (`go.mod` source) — `go` + `git` are pre-installed; Squadron runs `go build` per plugin. The Debian image copies Go 1.25 from the builder stage (bookworm's distro Go is too old); the Alpine image uses the distro Go.

Pre-built / released plugins (`source = "github.com/..."` or `source = "npm:..."`) work without these toolchains, so if you only use released plugins you can build your own slim image by removing the relevant packages from the Dockerfile.
