# Infrastructure Setup > **Where you are in the setup process:** > 1. [Main Installation](../README.md) - Clone repo, install dependencies > 2. **Infrastructure Setup** (YOU ARE HERE) - Docker, Chroma, Ollama, OpenRouter > 3. [Emacs Configuration](Emacs-Configuration.md) - Configure Emacs to use infrastructure > 4. [Troubleshooting](Troubleshooting.md) - When things go wrong This guide walks you through setting up the infrastructure components that power hive-mcp's advanced features. **No prior Docker or Ollama experience required** - every command is copy-paste ready with expected outputs shown. ## What You'll Set Up | Component | Purpose | Required? | |-----------|---------|-----------| | **Chroma** | Vector database for semantic memory search | Optional but recommended | | **Ollama** | Local AI for embeddings (privacy-focused) | Optional but recommended | | **OpenRouter** | Cloud LLM API for agent delegation | Optional | | **Systemd Services** | Standalone nREPL (optional, can conflict) | Optional | | **Observability Stack** | Metrics, logs, dashboards | Optional | **Without infrastructure:** Memory works with keyword/tag searches only **With Chroma + Ollama:** Memory uses semantic search (find by meaning) **With OpenRouter:** Can delegate coding tasks to cheaper models --- ## Prerequisites Check Before starting, verify you have the core hive-mcp installation working: ```bash # Check Claude Code CLI is installed claude --version ``` **Expected output:** ``` Claude Code v1.x.x ``` ```bash # Check Emacs daemon is running emacsclient -e '(emacs-version)' ``` **Expected output:** ``` "GNU Emacs 28.x" (or higher) ``` If either fails, complete the [main installation](Home.md) first. --- ## 1. Docker Setup (For Chroma Vector Database) ### Why Docker? Docker lets you run Chroma (and the observability stack) in isolated containers. This means: - **No system pollution** - software lives in containers, not on your system - **Easy cleanup** - `docker compose down` removes everything - **Reproducible** - same setup works on any machine ### Step 1.1: Install Docker **Ubuntu/Debian:** ```bash # Remove old versions (safe to run even if none exist) sudo apt-get remove docker docker-engine docker.io containerd runc 2>/dev/null || true # Install prerequisites sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg # Add Docker's official GPG key sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg # Add Docker repository echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # Install Docker sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # Add yourself to docker group (avoids needing sudo) sudo usermod -aG docker $USER ``` **IMPORTANT:** Log out and back in (or run `newgrp docker`) for group change to take effect. **macOS:** ```bash # Install via Homebrew brew install --cask docker # Start Docker Desktop from Applications folder # Wait for whale icon in menu bar to stop animating ``` ### Step 1.2: Verify Docker Installation ```bash docker --version ``` **Expected output:** ``` Docker version 24.0.x, build xxxxxxx ``` ```bash docker compose version ``` **Expected output:** ``` Docker Compose version v2.x.x ``` ```bash # Test Docker works without sudo docker run hello-world ``` **Expected output:** ``` Hello from Docker! This message shows that your installation appears to be working correctly. ... ``` **If you see "permission denied":** You need to log out and back in, or run `newgrp docker`. --- ## 2. Chroma Vector Database ### Why Chroma? Chroma stores **embeddings** (numerical representations of text) that enable semantic search. Instead of exact keyword matching, you can find memories by *meaning*: ``` Query: "how do we handle authentication?" Finds: "JWT tokens with refresh mechanism" (no keyword match, but semantically related) ``` ### Step 2.1: Start Chroma ```bash # Navigate to hive-mcp directory cd /path/to/hive-mcp # Start only Chroma (not the full stack) docker compose up -d chroma ``` **Expected output:** ``` [+] Running 2/2 ✔ Network hive-mcp_default Created ✔ Container emacs-mcp-chroma Started ``` ### Step 2.2: Verify Chroma is Running ```bash curl http://localhost:8000/api/v1/heartbeat ``` **Expected output:** ```json {"nanosecond heartbeat":1234567890} ``` The exact number doesn't matter - any JSON response means Chroma is healthy. ```bash # Check container status docker ps --filter "name=emacs-mcp-chroma" ``` **Expected output:** ``` CONTAINER ID IMAGE STATUS PORTS abc123... chromadb/chroma:latest Up X minutes 0.0.0.0:8000->8000/tcp ``` ### Step 2.3: Configure Emacs for Chroma The Emacs-side configuration is covered in detail in **[Emacs-Configuration.md](Emacs-Configuration.md)**. The key variables you'll set: | Variable | Value | Purpose | |----------|-------|---------| | `hive-mcp-chroma-host` | `"localhost"` | Where Chroma runs | | `hive-mcp-chroma-port` | `8000` | Chroma HTTP port | | `hive-mcp-chroma-embedding-provider` | `'ollama` | Use local Ollama | | `hive-mcp-chroma-ollama-model` | `"nomic-embed-text"` | Embedding model | **Note:** Complete the Ollama setup (Section 3) before configuring embeddings in Emacs. ### Chroma Troubleshooting **"Connection refused" on port 8000:** ```bash # Check if container is running docker ps -a --filter "name=emacs-mcp-chroma" # If Exited, check logs docker logs emacs-mcp-chroma # Restart container docker compose restart chroma ``` **"Port 8000 already in use":** ```bash # Find what's using port 8000 sudo lsof -i :8000 # Kill it or change Chroma's port in docker-compose.yml ``` --- ## 3. Ollama (Local Embeddings) ### Why Ollama? Ollama runs AI models **locally** on your machine. For hive-mcp, it: 1. **Generates embeddings** - converts text to vectors for Chroma 2. **Runs coding models** - optional local alternative to OpenRouter 3. **Preserves privacy** - your code never leaves your machine ### Step 3.1: Install Ollama **Linux:** ```bash curl -fsSL https://ollama.com/install.sh | sh ``` **Expected output:** ``` >>> Installing ollama to /usr/local/bin >>> Creating ollama user... >>> Adding ollama user to render group... >>> Adding current user to ollama group... >>> Creating systemd service... >>> Enabling systemd service... >>> Ollama installed successfully. ``` **macOS:** ```bash brew install ollama ``` ### Step 3.2: Start Ollama Service **Linux (systemd):** ```bash # Start the service sudo systemctl start ollama # Enable auto-start on boot sudo systemctl enable ollama ``` **macOS:** ```bash # Start in background ollama serve & ``` **Verify it's running:** ```bash curl http://localhost:11434/api/version ``` **Expected output:** ```json {"version":"0.x.x"} ``` ### Step 3.3: Download the Embedding Model ```bash ollama pull nomic-embed-text ``` **Expected output:** ``` pulling manifest pulling 970aa74c0a90... 100% ▕████████████████▏ 274 MB pulling c71d239df917... 100% ▕████████████████▏ 11 KB verifying sha256 digest writing manifest success ``` This downloads ~274MB. The model converts text into 768-dimensional vectors for semantic search. ### Step 3.4: Verify the Embedding Model ```bash # Test that embeddings work curl http://localhost:11434/api/embeddings -d '{ "model": "nomic-embed-text", "prompt": "test embedding" }' ``` **Expected output:** ```json {"embedding":[0.123, -0.456, 0.789, ...]} ``` You should see a JSON object with an `embedding` array containing ~768 numbers. ### Step 3.5: (Optional) Download Coding Models If you want to delegate coding tasks to local models: ```bash # Recommended: devstral-small for code generation ollama pull devstral-small:24b # Alternative: faster but less capable ollama pull codellama:13b ``` **Note:** `devstral-small:24b` is ~14GB and requires ~16GB RAM. Use `codellama:13b` (~8GB) for less powerful machines. ### Verify Available Models ```bash ollama list ``` **Expected output:** ``` NAME ID SIZE MODIFIED nomic-embed-text:latest 970aa74c0a90 274 MB 2 minutes ago devstral-small:24b abc123def456 14 GB 5 minutes ago ``` ### Ollama Troubleshooting **"Connection refused" on port 11434:** ```bash # Check if Ollama is running pgrep -f ollama # Start it manually ollama serve ``` **"Model not found" when pulling:** ```bash # Check available models at ollama.com/library # Model names are case-sensitive ollama pull nomic-embed-text # correct ollama pull Nomic-Embed-Text # WRONG ``` **Out of memory when running large models:** ```bash # Check available RAM free -h # Use smaller model ollama pull codellama:7b # Instead of 13b ``` --- ## 4. OpenRouter (Cloud LLM API) ### Why OpenRouter? OpenRouter provides access to many LLMs through a single API. hive-mcp uses it to: - **Delegate coding tasks** to cheaper models (saves expensive Claude tokens) - **Access free-tier models** for routine implementation work - **Switch models easily** based on task type ### Step 4.1: Get an API Key 1. Go to [openrouter.ai/keys](https://openrouter.ai/keys) 2. Sign in (or create account) 3. Click "Create Key" 4. Copy the key (starts with `sk-or-v1-`) ### Step 4.2: Set Environment Variable **Add to `~/.bashrc` (or `~/.zshrc`):** ```bash export OPENROUTER_API_KEY="sk-or-v1-YOUR-KEY-HERE" ``` **Apply changes:** ```bash source ~/.bashrc ``` ### Step 4.3: Verify the Key Works ```bash curl https://openrouter.ai/api/v1/models \ -H "Authorization: Bearer $OPENROUTER_API_KEY" \ | head -c 500 ``` **Expected output:** ```json {"data":[{"id":"openai/gpt-4o","name":"GPT-4o",... ``` Any JSON response (not an error) means your key works. ### Step 4.4: Understand Task-Type to Model Mapping hive-mcp automatically selects models based on task type: | Task Type | Default Model | Use Case | |-----------|---------------|----------| | `:coding` | `mistralai/devstral-2512:free` | Code generation, bug fixes | | `:coding-alt` | `google/gemma-3-4b-it:free` | Fallback for coding | | `:arch` | `xiaomi/mimo-v2-flash:free` | Architecture, design review | | `:docs` | `openai/gpt-oss-120b:free` | Documentation | **Free tier models cost $0** - perfect for routine tasks. ### Step 4.5: Test Delegation (Optional) From a Claude Code session: ``` > delegate to openrouter: write a hello world function in python ``` Claude will call `agent_delegate` with backend `openrouter`. ### OpenRouter Troubleshooting **"API key not found":** ```bash # Check if variable is set echo $OPENROUTER_API_KEY # If empty, re-export and restart terminal export OPENROUTER_API_KEY="sk-or-v1-..." # IMPORTANT: Restart MCP server to pick up new env ``` **"Model not valid" error:** ``` # OpenRouter uses format: provider/model-name:variant # Wrong: devstral-small:24b (Ollama format) # Right: mistralai/devstral-2512:free ``` --- ## 5. Systemd Services (Optional) ### hive-mcp-nrepl.service — Standalone nREPL A systemd user service that runs a standalone nREPL server in the hive-mcp project directory. **Location:** `~/.config/systemd/user/hive-mcp-nrepl.service` > **Warning: This service is optional and can interfere with the MCP server.** > > The MCP server (`server.clj`) starts its **own embedded nREPL** on port 7910 inside the same JVM as the channel server, event system, and swarm sync. bb-mcp connects to this embedded nREPL. > > If the systemd service starts first and grabs port 7910, bb-mcp will connect to a bare nREPL that has **no channel, no events, no swarm state**. Tool calls will fail silently and hivemind broadcasts go nowhere. **When to use it:** - Standalone REPL development (connecting CIDER without the full MCP server) - **Must use a different port than 7910** to avoid conflict with the MCP server **Service management:** ```bash # Check status systemctl --user status hive-mcp-nrepl.service # Start / stop / restart systemctl --user start hive-mcp-nrepl.service systemctl --user stop hive-mcp-nrepl.service # Enable / disable auto-start on login systemctl --user enable hive-mcp-nrepl.service systemctl --user disable hive-mcp-nrepl.service # View logs tail -f /tmp/hive-mcp-nrepl.log ``` **Common issues:** | Symptom | Cause | Fix | |---------|-------|-----| | `status=200/CHDIR` restart loop | `WorkingDirectory` path wrong | Fix path in unit file, `daemon-reload` | | `status=1/FAILURE` | Wrong `clojure` binary | Use `/usr/local/bin/clojure` (check `which clojure`) | | Port 7910 conflict with MCP | Both trying same port | Disable service or change its port | | Restart counter > 100 | Cascading from above | Fix root cause, then `systemctl --user reset-failed` | **History:** Originally named `emacs-mcp-nrepl.service`. Renamed to `hive-mcp-nrepl.service` after project rename (2026-01-27). --- ## 6. Observability Stack (Optional) ### Why Observability? The observability stack lets you: - **Monitor metrics** - track swarm performance, wave success rates - **Search logs** - find what went wrong in past sessions - **Visualize dashboards** - see system health at a glance **Components:** | Service | Port | Purpose | |---------|------|---------| | Prometheus | 9090 | Metrics collection | | Grafana | 3000 | Dashboards | | Loki | 3100 | Log aggregation | | Promtail | - | Ships logs to Loki | ### Step 5.1: Create External Volumes (Required for Milvus) The docker-compose includes Milvus (alternative vector DB). Even if you don't use it, the volumes must exist: ```bash docker volume create emacs-mcp_milvus-etcd docker volume create emacs-mcp_milvus-minio docker volume create emacs-mcp_milvus-data ``` **Expected output (for each):** ``` emacs-mcp_milvus-etcd ``` ### Step 5.2: Start the Observability Stack ```bash cd /path/to/hive-mcp # Start Prometheus, Grafana, Loki, Promtail docker compose up -d prometheus grafana loki promtail ``` **Expected output:** ``` [+] Running 5/5 ✔ Container emacs-mcp-loki Started ✔ Container emacs-mcp-prometheus Started ✔ Container emacs-mcp-promtail Started ✔ Container emacs-mcp-grafana Started ``` ### Step 5.3: Verify Services **Prometheus:** ```bash curl http://localhost:9090/-/ready ``` **Expected output:** ``` Prometheus Server is Ready. ``` **Grafana:** ```bash curl -s http://localhost:3000/api/health | jq . ``` **Expected output:** ```json { "commit": "...", "database": "ok", "version": "..." } ``` **Loki:** ```bash curl http://localhost:3100/ready ``` **Expected output:** ``` ready ``` ### Step 5.4: Access Grafana Dashboard 1. Open [http://localhost:3000](http://localhost:3000) in your browser 2. Login with: - **Username:** `admin` - **Password:** `hivemcp` 3. Navigate to Dashboards to explore hive-mcp metrics ### Step 5.5: Query Logs via CLI Using the MCP tools from Claude: ``` > query loki for recent errors: {job="hive-mcp"} |= "error" ``` Or directly: ```bash curl -G -s "http://localhost:3100/loki/api/v1/query_range" \ --data-urlencode 'query={job="hive-mcp"}' \ --data-urlencode 'limit=10' \ | jq '.data.result[0].values' ``` ### Observability Troubleshooting **Grafana shows "No data":** ```bash # Check Prometheus can reach hive-mcp curl http://localhost:9999/metrics # If connection refused, MCP server isn't exposing metrics # Metrics endpoint may need to be enabled in config ``` **Logs not appearing in Loki:** ```bash # Check promtail is reading log files docker logs emacs-mcp-promtail # Verify log directory exists ls ~/.config/hive-mcp/ ``` --- ## 7. Full Stack Quick Start To start everything at once: ```bash cd /path/to/hive-mcp # Create required external volumes docker volume create emacs-mcp_milvus-etcd docker volume create emacs-mcp_milvus-minio docker volume create emacs-mcp_milvus-data # Start all services docker compose up -d ``` **Expected output:** ``` [+] Running 10/10 ✔ Container emacs-mcp-chroma Started ✔ Container emacs-mcp-milvus-etcd Started ✔ Container emacs-mcp-milvus-minio Started ✔ Container emacs-mcp-milvus Started ✔ Container emacs-mcp-loki Started ✔ Container emacs-mcp-prometheus Started ✔ Container emacs-mcp-promtail Started ✔ Container emacs-mcp-grafana Started ``` ### Verify Everything ```bash # All containers running docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" ``` **Expected output:** ``` NAMES STATUS PORTS emacs-mcp-chroma Up X minutes 0.0.0.0:8000->8000/tcp emacs-mcp-grafana Up X minutes 0.0.0.0:3000->3000/tcp emacs-mcp-prometheus Up X minutes 0.0.0.0:9090->9090/tcp emacs-mcp-loki Up X minutes 0.0.0.0:3100->3100/tcp emacs-mcp-promtail Up X minutes ``` --- ## 8. Stopping and Cleanup ### Stop All Services (Keep Data) ```bash docker compose down ``` ### Stop and Remove All Data ```bash docker compose down -v ``` **Warning:** This deletes all stored vectors, metrics, and logs. --- ## 9. Backup and Maintenance ### Automated Chroma Backup Protect your memory database with daily backups: ```bash # Manual backup (run anytime) ./scripts/backup-chroma.sh ``` **Expected output:** ``` Backup complete: /home/user/backups/chroma/chroma-20260122.sqlite3 -rw-r--r-- 1 user user 8.0M Jan 22 22:43 /home/user/backups/chroma/chroma-20260122.sqlite3 ``` ### Install Daily Cron Job ```bash # Install cron to run backup daily at 3am ./scripts/install-backup-cron.sh ``` **Verify cron is installed:** ```bash crontab -l | grep backup-chroma ``` **Expected output:** ``` 0 3 * * * /path/to/hive-mcp/scripts/backup-chroma.sh >> /home/user/backups/chroma/backup.log 2>&1 ``` ### Backup Details | Setting | Value | |---------|-------| | Backup location | `~/backups/chroma/` | | Filename format | `chroma-YYYYMMDD.sqlite3` | | Retention | 7 days (older auto-deleted) | | Log file | `~/backups/chroma/backup.log` | ### Restore from Backup ```bash # Stop Chroma docker compose stop chroma # Copy backup into container volume docker cp ~/backups/chroma/chroma-20260122.sqlite3 hive-mcp-chroma:/data/chroma.sqlite3 # Restart Chroma docker compose start chroma ``` --- ### Remove Specific Services ```bash # Stop just observability docker compose down prometheus grafana loki promtail # Keep Chroma running docker compose up -d chroma ``` --- ## Quick Reference Card ### Essential Commands | Action | Command | |--------|---------| | Start Chroma only | `docker compose up -d chroma` | | Start full stack | `docker compose up -d` | | Stop everything | `docker compose down` | | Check container status | `docker ps` | | View container logs | `docker logs ` | | Test Chroma | `curl localhost:8000/api/v1/heartbeat` | | Test Ollama | `curl localhost:11434/api/version` | | List Ollama models | `ollama list` | | Pull embedding model | `ollama pull nomic-embed-text` | | Backup Chroma | `./scripts/backup-chroma.sh` | | Install backup cron | `./scripts/install-backup-cron.sh` | ### Service Ports | Service | URL | |---------|-----| | Chroma | http://localhost:8000 | | Ollama | http://localhost:11434 | | Grafana | http://localhost:3000 | | Prometheus | http://localhost:9090 | | Loki | http://localhost:3100 | ### Default Credentials | Service | Username | Password | |---------|----------|----------| | Grafana | admin | hivemcp | --- ## What's Next? You've set up the infrastructure. Now configure Emacs to use it: ### Recommended Reading Order 1. **[Emacs-Configuration.md](Emacs-Configuration.md)** (DO THIS NEXT) - Load paths, addons, and WebSocket channel - Variable reference for Chroma, Swarm, CIDER - Verification steps to confirm everything works 2. **[Troubleshooting.md](Troubleshooting.md)** (BOOKMARK THIS) - Symptom-based problem solving - Quick diagnostics one-liner - Solutions for Docker, Ollama, OpenRouter issues 3. **[Home.md](Home.md)** - Full wiki index for other topics ### Quick Test Before Moving On Before proceeding to Emacs configuration, verify your infrastructure: ```bash # All three should succeed curl -s http://localhost:8000/api/v1/heartbeat && echo " Chroma OK" curl -s http://localhost:11434/api/version && echo " Ollama OK" echo $OPENROUTER_API_KEY | grep -q "sk-or" && echo " OpenRouter key set" ``` If any fail, fix them now using the troubleshooting sections above.