-
Notifications
You must be signed in to change notification settings - Fork 3
Infrastructure Setup
Where you are in the setup process:
- Main Installation - Clone repo, install dependencies
- Infrastructure Setup (YOU ARE HERE) - Docker, Chroma, Ollama, OpenRouter
- Emacs Configuration - Configure Emacs to use infrastructure
- 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.
| 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
Before starting, verify you have the core hive-mcp installation working:
# Check Claude Code CLI is installed
claude --versionExpected 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.
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 downremoves everything - Reproducible - same setup works on any machine
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 $USERIMPORTANT: 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 animatingdocker --versionExpected output:
Docker version 24.0.x, build xxxxxxx
docker compose versionExpected output:
Docker Compose version v2.x.x
# Test Docker works without sudo
docker run hello-worldExpected 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.
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)
# Navigate to hive-mcp directory
cd /path/to/hive-mcp
# Start only Chroma (not the full stack)
docker compose up -d chromaExpected output:
[+] Running 2/2
✔ Network hive-mcp_default Created
✔ Container emacs-mcp-chroma Started
curl http://localhost:8000/api/v1/heartbeatExpected 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
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.
"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.ymlOllama runs AI models locally on your machine. For hive-mcp, it:
- Generates embeddings - converts text to vectors for Chroma
- Runs coding models - optional local alternative to OpenRouter
- Preserves privacy - your code never leaves your machine
Linux:
curl -fsSL https://ollama.com/install.sh | shExpected 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 ollamaLinux (systemd):
# Start the service
sudo systemctl start ollama
# Enable auto-start on boot
sudo systemctl enable ollamamacOS:
# Start in background
ollama serve &Verify it's running:
curl http://localhost:11434/api/versionExpected output:
{"version":"0.x.x"}ollama pull nomic-embed-textExpected 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.
# 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.
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:13bNote: devstral-small:24b is ~14GB and requires ~16GB RAM. Use codellama:13b (~8GB) for less powerful machines.
ollama listExpected output:
NAME ID SIZE MODIFIED
nomic-embed-text:latest 970aa74c0a90 274 MB 2 minutes ago
devstral-small:24b abc123def456 14 GB 5 minutes ago
"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 # WRONGOut of memory when running large models:
# Check available RAM
free -h
# Use smaller model
ollama pull codellama:7b # Instead of 13bOpenRouter 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
- Go to openrouter.ai/keys
- Sign in (or create account)
- Click "Create Key"
- Copy the key (starts with
sk-or-v1-)
Add to ~/.bashrc (or ~/.zshrc):
export OPENROUTER_API_KEY="sk-or-v1-YOUR-KEY-HERE"Apply changes:
source ~/.bashrccurl https://openrouter.ai/api/v1/models \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
| head -c 500Expected output:
{"data":[{"id":"openai/gpt-4o","name":"GPT-4o",...Any JSON response (not an error) means your key works.
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.
From a Claude Code session:
> delegate to openrouter: write a hello world function in python
Claude will call agent_delegate with backend openrouter.
"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
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.logCommon 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).
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 |
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-dataExpected output (for each):
emacs-mcp_milvus-etcd
cd /path/to/hive-mcp
# Start Prometheus, Grafana, Loki, Promtail
docker compose up -d prometheus grafana loki promtailExpected output:
[+] Running 5/5
✔ Container emacs-mcp-loki Started
✔ Container emacs-mcp-prometheus Started
✔ Container emacs-mcp-promtail Started
✔ Container emacs-mcp-grafana Started
Prometheus:
curl http://localhost:9090/-/readyExpected 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/readyExpected output:
ready
- Open http://localhost:3000 in your browser
- Login with:
-
Username:
admin -
Password:
hivemcp
-
Username:
- Navigate to Dashboards to explore hive-mcp metrics
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'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 configLogs not appearing in Loki:
# Check promtail is reading log files
docker logs emacs-mcp-promtail
# Verify log directory exists
ls ~/.config/hive-mcp/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 -dExpected 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
# 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
docker compose downdocker compose down -vWarning: This deletes all stored vectors, metrics, and logs.
Protect your memory database with daily backups:
# Manual backup (run anytime)
./scripts/backup-chroma.shExpected 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 cron to run backup daily at 3am
./scripts/install-backup-cron.shVerify cron is installed:
crontab -l | grep backup-chromaExpected output:
0 3 * * * /path/to/hive-mcp/scripts/backup-chroma.sh >> /home/user/backups/chroma/backup.log 2>&1
| Setting | Value |
|---|---|
| Backup location | ~/backups/chroma/ |
| Filename format | chroma-YYYYMMDD.sqlite3 |
| Retention | 7 days (older auto-deleted) |
| Log file | ~/backups/chroma/backup.log |
# 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# Stop just observability
docker compose down prometheus grafana loki promtail
# Keep Chroma running
docker compose up -d chroma| 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 | URL |
|---|---|
| Chroma | http://localhost:8000 |
| Ollama | http://localhost:11434 |
| Grafana | http://localhost:3000 |
| Prometheus | http://localhost:9090 |
| Loki | http://localhost:3100 |
| Service | Username | Password |
|---|---|---|
| Grafana | admin | hivemcp |
You've set up the infrastructure. Now configure Emacs to use it:
-
Emacs-Configuration.md (DO THIS NEXT)
- Load paths, addons, and WebSocket channel
- Variable reference for Chroma, Swarm, CIDER
- Verification steps to confirm everything works
-
Troubleshooting.md (BOOKMARK THIS)
- Symptom-based problem solving
- Quick diagnostics one-liner
- Solutions for Docker, Ollama, OpenRouter issues
-
Home.md - Full wiki index for other topics
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.