# Conjurer Deployment Guide

This document walks through deploying the Conjurer stack (Discord bot, music
service, librarian service) on two Raspberry Pi 4s and one Windows host, first
with plain Docker Compose, then with a future Kubernetes setup.

## 1. Current Hardware Layout

- **Windows PC**: Stores persistent data (JSON memories, configs, music
  catalogue). Shares folders over the network (SMB) for the Pis.
- **Raspberry Pi A** (“radio”): Runs the Liquidsoap/liq radio pipeline and the
  musician service (Flask + file watcher).
- **Raspberry Pi B** (“bot”): Runs the Discord bot, communication bridge, and
  librarian Flask service.

You can rebalance as follows:

| Service             | Recommended Host | Notes |
|---------------------|------------------|-------|
| Discord bot + comms | Raspberry Pi B   | Needs outbound internet, moderate CPU |
| Librarian service   | Raspberry Pi B   | CPU-heavy during Crossref queries; keep close to bot |
| Musician service    | Raspberry Pi A   | Has direct disk access to music, same box as Liquidsoap |
| Data storage        | Windows          | Expose via SMB; mount inside containers |

## 2. Prepare Shared Storage on Windows

1. Create directories, e.g. `C:\Conjurer\config`, `C:\Conjurer\logs`,
   `C:\Conjurer\music`, `C:\Conjurer\playlists`, `C:\Conjurer\secrets`.
2. Copy your existing JSON settings (`settings.json`, `pamiec.json`,
   `pamiec_muzyki.json`, `system_gpt_settings.json`, etc.) into `config`.
3. Create blank placeholder files if they do not exist yet.
4. Share the root folder (`C:\Conjurer`) over SMB with read/write access for the
   Pi user (create credentials if necessary).

## 3. Configure Environment Files

1. On your workstation, copy the example env files:
   ```bash
   cp docker/env/bot.env.example docker/env/bot.env
   cp docker/env/musician.env.example docker/env/musician.env
   cp docker/env/librarian.env.example docker/env/librarian.env
   ```
2. Edit each `docker/env/*.env` to replace `HACKME!` with real values:
   - `DISCORD_TOKEN`, `OPENAI_API_KEY`, `CONJURER_API_KEY` (use the same value for
     all services).
   - `ANTHROPIC_API_KEY` — only if you want the Claude backend (see “AI backend
     switch” below). Safe to leave unset while running on GPT.
   - For musician/librarian, adjust mounts to the SMB paths you will mount on the
     Pis, e.g. `/mnt/conjurer/music`.
   - Set `CONJURER_CROSSREF_MAILTO` to a real email as required by Crossref.
3. If you rely on `.netrc`, copy it to `C:\Conjurer\secrets\.netrc` and set
   `CONJURER_NETRC_FILE` accordingly. The bot reads netrc machines `discord`,
   `openai`, `anthropic`, `assemblyai`, `spotipy`, `youtube`.

### AI backend switch (GPT ↔ Claude)

The AI chat features run on one backend at a time, selected by a single switch:

- **Startup:** `CONJURER_AI_CONFIG=gpt` (default) or `=claude` in `bot.env`. Unset
  falls back to the `"active"` key in `system_gpt_settings.json`, then `"gpt"`.
- **Runtime:** the `$gadaj_teraz <config>` Discord command (Vykidailo only) flips
  the backend live and persists the choice.
- The named configs (which provider, which models) live in
  `system_gpt_settings.json` — add more there. Claude needs `ANTHROPIC_API_KEY`;
  GPT needs `OPENAI_API_KEY`. Image generation (`imaginuje sobie:`) and personal
  assistants always use OpenAI regardless of the switch (Anthropic has no
  equivalent), and degrade quietly if `OPENAI_API_KEY` is absent.

## 4. Install Docker on Raspberry Pis and Windows

### Raspberry Pi
```bash
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
sudo reboot

# Install docker compose plugin
sudo apt-get install docker-compose-plugin
```

### Windows
- Install **Docker Desktop**.
- Enable WSL2 backend and expose the shared Windows folders to the containers
  (Docker Desktop settings → Resources → File Sharing).

## 5. Deploy Musician Service (Pi A)

1. SSH into Raspberry Pi A.
2. Mount the Windows SMB share:
   ```bash
   sudo mkdir -p /mnt/conjurer
   sudo apt-get install cifs-utils
   sudo mount -t cifs //WINDOWS_HOST/Conjurer /mnt/conjurer -o user=YOURUSER
   ```
   Add an entry to `/etc/fstab` for persistence.
3. Copy the repo to the Pi or `git clone` it.
4. On Pi A, create override compose file (optional) pointing volumes to
   `/mnt/conjurer`.
5. Start only the musician service:
   ```bash
   docker compose up --build -d musician
   ```
   Alternatively, duplicate `docker-compose.yml`, strip other services, and run
   `docker compose up -d`.

## 6. Deploy Bot + Librarian (Pi B)

1. Repeat SMB mount on Pi B (same mount path).
2. Copy repo / pull latest changes.
3. Create `.env` files with tokens (or copy from control machine).
4. Start bot and librarian:
   ```bash
   docker compose up -d bot librarian
   ```

## 7. Optional: Run Supporting Liquidsoap Radio

- Keep Liquidsoap on Pi A as-is, using the same music directories. Ensure the
  musician container has read access to those directories (bind mount).

## 8. Verifying

1. `docker ps` on each Pi to confirm containers running.
2. Inspect logs under the mounted logs directory (`/mnt/conjurer/logs`).
3. Join Discord server; issue commands to confirm functionality.
4. Hit health endpoints manually (e.g. `curl http://PIB:5000/conjurer`).

## Rebalancing Suggestions

- If librarian CPU spikes become an issue, move it to Pi A or another host.
- If you add a dedicated NAS, mount the network share read-only for the musician
  container and read/write for other services.

## 9. Future Kubernetes Deployment (Outline)

### Hardware Considerations

- Minimum three nodes for HA: use the existing two Pis plus one additional Pi 4
  (8 GB preferred). Use Windows PC as storage provider via NFS/SMB CSI driver or
  as a data gateway.
- Consider Pi clusters with USB SSDs for better I/O.

### Cluster Setup Steps

1. Install a lightweight Kubernetes distribution (e.g., k3s) on each Pi:
   ```bash
   curl -sfL https://get.k3s.io | sh -
   # On additional nodes
   curl -sfL https://get.k3s.io | K3S_URL=https://MASTER:6443 K3S_TOKEN=HACKME sh -
   ```
2. Install MetalLB for load balancer support on LAN.
3. Configure persistent volumes using:
   - `nfs-subdir-external-provisioner` pointing to Windows share (ensure Windows
     host supports NFS or run an NFS gateway on another machine).
   - Alternatively, attach individual USB drives to each Pi and use
     `local-path-provisioner` for node-local storage.
4. Create Kubernetes `Secret` objects for tokens (`DISCORD_TOKEN`, etc.).
5. Define `Deployment` manifests for each service (bot, musician, librarian) and
   associated `Services`.
6. Expose Discord bot ports via `NodePort` or Ingress.
7. Use `StatefulSet` if you need stable identity for the musician service (due to
   local storage).

### Optimisation Tips

- Keep CPU-heavy librarian pods optionally on a beefier node; use
  `nodeSelector`/`affinity` to pin workloads.
- Consider splitting the persistent storage: music on Pi A (USB disk), logs and
  configs on Pi B, backups on Windows.
- For improved reliability, add at least one extra Pi for quorum and to host the
  communication bridge if the bot node fails.

## Summary Checklist

1. Prepare Windows shares & tokens.
2. Configure `docker/env/*.env` using `HACKME!` templates as reference.
3. Install Docker on Pis, mount network shares.
4. Launch musician on Pi A, bot + librarian on Pi B.
5. Verify Discord functionality and API endpoints.
6. Plan Kubernetes migration when ready (k3s + MetalLB + storage provisioner).
