Skip to content

Infrastructure Setup

Pedro Gomes Branquinho edited this page Feb 15, 2026 · 1 revision

Infrastructure Setup

Where you are in the setup process:

  1. Main Installation - Clone repo, install dependencies
  2. Infrastructure Setup (YOU ARE HERE) - Docker, Chroma, Ollama, OpenRouter
  3. Emacs Configuration - Configure Emacs to use infrastructure
  4. Troubleshooting - 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:

# Check Claude Code CLI is installed
claude --version

Expected output:

Claude Code v1.x.x
# Check Emacs daemon is running
emacsclient -e '(emacs-version)'

Expected output:

"GNU Emacs 28.x" (or higher)

If either fails, complete the main installation 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:

# 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:

# 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

docker --version

Expected output:

Docker version 24.0.x, build xxxxxxx
docker compose version

Expected output:

Docker Compose version v2.x.x
# 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

# 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

curl http://localhost:8000/api/v1/heartbeat

Expected output:

{"nanosecond heartbeat":1234567890}

The exact number doesn't matter - any JSON response means Chroma is healthy.

# 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. 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:

# 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":

# 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:

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:

brew install ollama

Step 3.2: Start Ollama Service

Linux (systemd):

# Start the service
sudo systemctl start ollama

# Enable auto-start on boot
sudo systemctl enable ollama

macOS:

# Start in background
ollama serve &

Verify it's running:

curl http://localhost:11434/api/version

Expected output:

{"version":"0.x.x"}

Step 3.3: Download the Embedding Model

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

# Test that embeddings work
curl http://localhost:11434/api/embeddings -d '{
  "model": "nomic-embed-text",
  "prompt": "test embedding"
}'

Expected output:

{"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:

# 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

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:

# Check if Ollama is running
pgrep -f ollama

# Start it manually
ollama serve

"Model not found" when pulling:

# 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:

# 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
  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):

export OPENROUTER_API_KEY="sk-or-v1-YOUR-KEY-HERE"

Apply changes:

source ~/.bashrc

Step 4.3: Verify the Key Works

curl https://openrouter.ai/api/v1/models \
  -H "Authorization: Bearer $OPENROUTER_API_KEY" \
  | head -c 500

Expected output:

{"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":

# 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:

# 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:

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

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:

curl http://localhost:9090/-/ready

Expected output:

Prometheus Server is Ready.

Grafana:

curl -s http://localhost:3000/api/health | jq .

Expected output:

{
  "commit": "...",
  "database": "ok",
  "version": "..."
}

Loki:

curl http://localhost:3100/ready

Expected output:

ready

Step 5.4: Access Grafana Dashboard

  1. Open 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:

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":

# 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:

# 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:

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

# 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)

docker compose down

Stop and Remove All Data

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:

# 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

# Install cron to run backup daily at 3am
./scripts/install-backup-cron.sh

Verify cron is installed:

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

# 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

# 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 <container-name>
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 (DO THIS NEXT)

    • Load paths, addons, and WebSocket channel
    • Variable reference for Chroma, Swarm, CIDER
    • Verification steps to confirm everything works
  2. Troubleshooting.md (BOOKMARK THIS)

    • Symptom-based problem solving
    • Quick diagnostics one-liner
    • Solutions for Docker, Ollama, OpenRouter issues
  3. Home.md - Full wiki index for other topics

Quick Test Before Moving On

Before proceeding to Emacs configuration, verify your infrastructure:

# 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.

Clone this wiki locally