nanobot/DOCKER_MULTI_BOT_GUIDE.md
tanyar09 4b808f9a30 Docs: MCP local clones and tool profiles
Document local-cloned MCP server layout, docker mounts, tool-call JSON protocol for local providers, profile routing behavior, and common gotchas. Add a brief pointer from the multi-bot Docker guide.

Made-with: Cursor
2026-03-31 12:53:34 -04:00

658 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Docker Multi-Bot Setup Guide
Complete guide for running multiple nanobot instances with Docker, each with its own Telegram bot.
## 📋 Table of Contents
1. [Quick Start](#quick-start)
2. [Architecture Overview](#architecture-overview)
3. [Setup Instructions](#setup-instructions)
4. [Running Bots](#running-bots)
5. [Configuration Management](#configuration-management)
6. [Development Workflow](#development-workflow)
7. [Troubleshooting](#troubleshooting)
8. [Reference](#reference)
---
## Quick Start
### Start Only User1 Bot
```bash
docker compose -f docker-compose.multi.env.yml up -d nanobot-user1
```
### Start All Bots
```bash
docker compose -f docker-compose.multi.env.yml up -d
```
### Stop All Bots
```bash
docker compose -f docker-compose.multi.env.yml down
```
### Stop Specific Bot
```bash
docker compose -f docker-compose.multi.env.yml stop nanobot-user1
```
### View Logs
```bash
docker logs -f nanobot-user1
```
---
## Architecture Overview
### How It Works
Each bot runs in its own Docker container with:
- **Separate config directory**: `~/.nanobot-user1`, `~/.nanobot-user2`, etc.
- **Shared env file**: `.env.shared` (common settings)
- **Bot-specific env file**: `.env.user1`, `.env.user2`, etc. (overrides)
- **Isolated environment**: No conflicts between bots
### File Structure
```
nanobot/
├── .env.shared # Shared settings (API keys, model, etc.)
├── .env.user1 # Bot 1 (@ilia) overrides
├── .env.user2 # Bot 2 (@family) overrides
├── .env.user3 # Bot 3 (@wife) overrides
├── agent_workspaces/ # Templates copied by scripts/init-agent-workspaces.sh
├── scripts/init-agent-workspaces.sh
├── docker-compose.multi.env.yml # Production compose file
├── docker-compose.multi.dev.yml # Development compose file
├── ~/.nanobot/workspaces/
│ ├── ilia/ # Mounted as /workspace for user1 — AGENTS.md, memory/, …
│ ├── family/ # user2
│ └── wife/ # user3
├── ~/.nanobot-user1/
│ └── config.json # Bot 1 channel config (Telegram token, allowFrom)
├── ~/.nanobot-user2/
│ └── config.json # Bot 2 channel config
└── ~/.nanobot-user3/
└── config.json # Bot 3 channel config
```
`./workspace` in the repo remains for **single-bot** `docker-compose.yml` only; multi-bot uses `~/.nanobot/workspaces/*` per container.
### Configuration Loading
1. **Docker Compose** loads environment files:
- First: `.env.shared` (shared settings)
- Second: `.env.userX` (bot-specific overrides)
- Later files override earlier ones
2. **Container** mounts config directory:
- Host: `~/.nanobot-user1` → Container: `/root/.nanobot`
3. **Nanobot** loads:
- Environment variables (from Docker env files)
- Config file: `/root/.nanobot/config.json` (mounted from host)
### MCP servers + tool profiles (local LLM note)
If youre using a local LLM provider with a **low tool limit** (often ~20 tools), MCP servers (which can register 30+ tools) can exceed the limit unless you use tool profiles carefully.
See `docs/mcp_local_clone_and_tool_profiles.md` for:
- Local-clone MCP layout (`./mcp-servers``/app/mcp-servers`)
- How MCP env vars like `$NANOBOT_GITLE_TOKEN` are expanded into server env
- Tool-call JSON protocol for local providers
- Profile routing behavior and when MCP servers disconnect
---
## Setup Instructions
### Step 0: Per-agent workspaces (personalities + isolated memory)
Multi-bot compose mounts **separate** workspace directories so each bot has its own `AGENTS.md`, `SOUL.md`, `USER.md`, and `memory/` (no shared `./workspace`).
On the host, from the repo root:
```bash
./scripts/init-agent-workspaces.sh
```
This creates:
```
~/.nanobot/workspaces/
ilia/ # nanobot-user1 — dev / infra persona
family/ # nanobot-user2 — household persona
wife/ # nanobot-user3 — personal assistant persona
```
Templates live in-repo under `agent_workspaces/`. Re-run the script anytime: it **skips** files that already exist. Adjust ownership if Docker runs as root:
```bash
sudo chown -R "$(whoami):$(whoami)" ~/.nanobot/workspaces
```
### Step 1: Create Environment Files
Run the setup script:
```bash
./env-files-setup.sh
```
This creates:
- `.env.shared` - Shared settings
- `.env.user1`, `.env.user2`, `.env.user3` - Bot-specific overrides
### Step 2: Edit `.env.shared`
Add your shared settings:
```bash
nano .env.shared
```
Example:
```bash
# Provider Settings
NANOBOT_PROVIDERS__CUSTOM__API_KEY=no-key
NANOBOT_PROVIDERS__CUSTOM__API_BASE=http://172.17.0.1:11434/v1
# Agent Settings
NANOBOT_AGENTS__DEFAULTS__MODEL=llama3.1:8b
NANOBOT_AGENTS__DEFAULTS__WORKSPACE=/mnt/data/nanobot
NANOBOT_AGENTS__DEFAULTS__TEMPERATURE=0.7
```
**Important**: Use `172.17.0.1` (Docker bridge gateway) instead of `localhost` so containers can reach Ollama on the host.
### Step 3: Edit Bot-Specific Env Files
Edit `.env.user1`, `.env.user2`, etc. with bot-specific settings:
```bash
nano .env.user1
```
Example:
```bash
# Telegram Bot Token
NANOBOT_CHANNELS__TELEGRAM__ENABLED=true
NANOBOT_CHANNELS__TELEGRAM__TOKEN=your_bot_token_here
# Email Credentials (if different per bot)
NANOBOT_CHANNELS__EMAIL__IMAP_USERNAME=bot1@example.com
NANOBOT_CHANNELS__EMAIL__IMAP_PASSWORD=password
```
### Step 4: Create Config Files
Run the config creation script:
```bash
./create-bot-configs.sh
```
Or manually create `~/.nanobot-user1/config.json`:
```json
{
"channels": {
"telegram": {
"enabled": true,
"allowFrom": ["YOUR_TELEGRAM_USERNAME"]
},
"email": {
"enabled": true,
"allowFrom": ["email@example.com"]
}
}
}
```
**Note**: `allowFrom` arrays must be in `config.json`, NOT in env files.
### Step 5: Build Docker Image
```bash
docker compose -f docker-compose.multi.env.yml build
```
---
## Running Bots
### Start Commands
```bash
# Start only user1
docker compose -f docker-compose.multi.env.yml up -d nanobot-user1
# Start only user2
docker compose -f docker-compose.multi.env.yml up -d nanobot-user2
# Start only user3
docker compose -f docker-compose.multi.env.yml up -d nanobot-user3
# Start all bots
docker compose -f docker-compose.multi.env.yml up -d
```
### Stop Commands
```bash
# Stop only user1
docker compose -f docker-compose.multi.env.yml stop nanobot-user1
# Stop only user2
docker compose -f docker-compose.multi.env.yml stop nanobot-user2
# Stop only user3
docker compose -f docker-compose.multi.env.yml stop nanobot-user3
# Stop all bots
docker compose -f docker-compose.multi.env.yml down
```
### Restart Commands
```bash
# Restart only user1
docker compose -f docker-compose.multi.env.yml restart nanobot-user1
# Restart all bots
docker compose -f docker-compose.multi.env.yml restart
```
### Status Commands
```bash
# Check what's running
docker compose -f docker-compose.multi.env.yml ps
# View logs for user1
docker logs -f nanobot-user1
# View logs for all bots
docker compose -f docker-compose.multi.env.yml logs -f
# View logs for specific bot
docker compose -f docker-compose.multi.env.yml logs -f nanobot-user1
```
### Remove Commands
```bash
# Stop and remove user1 container
docker compose -f docker-compose.multi.env.yml stop nanobot-user1
docker rm nanobot-user1
# Stop and remove all containers
docker compose -f docker-compose.multi.env.yml down
# Remove containers and volumes (keeps config files)
docker compose -f docker-compose.multi.env.yml down -v
```
---
## Configuration Management
### Updating Shared Settings
Edit `.env.shared`:
```bash
nano .env.shared
```
Restart affected containers:
```bash
docker compose -f docker-compose.multi.env.yml restart
```
### Updating Bot-Specific Settings
Edit `.env.userX`:
```bash
nano .env.user1
```
Restart that specific bot:
```bash
docker compose -f docker-compose.multi.env.yml restart nanobot-user1
```
### Updating Config Files
Edit config file:
```bash
nano ~/.nanobot-user1/config.json
```
Restart container:
```bash
docker restart nanobot-user1
```
### Adding Email to allowFrom
```bash
# Add email to user1's allowFrom
jq '.channels.email.allowFrom += ["newemail@example.com"]' \
~/.nanobot-user1/config.json > ~/.nanobot-user1/config.json.tmp && \
mv ~/.nanobot-user1/config.json.tmp ~/.nanobot-user1/config.json
# Restart container
docker restart nanobot-user1
```
### Environment Variable Format
Nanobot uses Pydantic's `BaseSettings` with:
- Prefix: `NANOBOT_`
- Nested delimiter: `__` (double underscore)
Examples:
- `NANOBOT_PROVIDERS__CUSTOM__API_KEY``providers.custom.apiKey`
- `NANOBOT_CHANNELS__TELEGRAM__TOKEN``channels.telegram.token`
- `NANOBOT_AGENTS__DEFAULTS__MODEL``agents.defaults.model`
---
## Development Workflow
### Option 1: Development Mode (Recommended)
Use `docker-compose.multi.dev.yml` which mounts source code:
```bash
# Start in development mode
docker compose -f docker-compose.multi.dev.yml up -d nanobot-user1
# Make changes in venv
source venv/bin/activate
nano nanobot/channels/telegram.py
# Restart container (picks up changes)
docker compose -f docker-compose.multi.dev.yml restart nanobot-user1
# View logs
docker logs -f nanobot-user1-dev
```
### Option 2: Rebuild After Changes
```bash
# Make changes
source venv/bin/activate
nano nanobot/channels/telegram.py
# Rebuild image
docker compose -f docker-compose.multi.env.yml build nanobot-user1
# Recreate container
docker compose -f docker-compose.multi.env.yml up -d --force-recreate nanobot-user1
```
### Option 3: Run on Host (Not Docker)
```bash
# Activate venv
source venv/bin/activate
# Run directly
nanobot gateway
```
**Note**: Host command uses:
- Config: `~/.nanobot/config.json` (original)
- .env: `.env` in current directory (NOT `.env.shared`)
---
## Troubleshooting
### Bot Not Responding
1. **Check if container is running**:
```bash
docker ps | grep nanobot-user1
```
2. **Check logs**:
```bash
docker logs nanobot-user1 --tail 50
```
3. **Verify Telegram token**:
```bash
grep TELEGRAM__TOKEN .env.user1
```
4. **Check allowFrom**:
```bash
cat ~/.nanobot-user1/config.json | jq '.channels.telegram.allowFrom'
```
### Connection Error (Ollama)
**Problem**: "Connection error" when bot tries to use LLM
**Solution**:
1. Check Ollama is running:
```bash
curl http://localhost:11434/api/tags
```
2. Verify API_BASE in `.env.shared`:
```bash
grep API_BASE .env.shared
```
Should be: `http://172.17.0.1:11434/v1` (NOT `localhost`)
3. Restart container:
```bash
docker restart nanobot-user1
```
### Config Not Loading
1. **Check volume mount**:
```bash
docker inspect nanobot-user1 | grep -A 5 Mounts
```
2. **Verify config exists**:
```bash
ls -lh ~/.nanobot-user1/config.json
```
3. **Check inside container**:
```bash
docker exec nanobot-user1 cat /root/.nanobot/config.json
```
### Environment Variables Not Applied
1. **Check env files are loaded**:
```bash
docker exec nanobot-user1 env | grep NANOBOT
```
2. **Recreate container** (env files loaded at creation):
```bash
docker compose -f docker-compose.multi.env.yml up -d --force-recreate nanobot-user1
```
### Port Already in Use
If port conflicts:
```bash
# Check what's using the port
sudo lsof -i :18790
# Stop conflicting container
docker stop <container_name>
# Or change port in docker-compose.multi.env.yml
```
---
## Reference
### Docker Compose Files
| File | Purpose | Use Case | Env Loading |
|------|---------|----------|-------------|
| `docker-compose.yml` | Single-bot baseline | One gateway + optional CLI, simplest setup | No `env_file`; uses mounted `~/.nanobot/config.json` and container environment |
| `docker-compose.multi.yml` | Multi-bot baseline | Multiple bots with separate config dirs, minimal env indirection | No `env_file`; each bot uses mounted `~/.nanobot-userX/config.json` and container environment |
| `docker-compose.multi.env.yml` | Multi-bot production | Stable multi-bot deployments with shared + per-bot overrides | Loads `.env.shared` first, then `.env.userX` (later file overrides earlier) |
| `docker-compose.multi.dev.yml` | Multi-bot development | Active code development with source mounted into containers | Same env behavior as `multi.env` (`.env.shared` + `.env.userX`) |
### Container Names
- `nanobot-user1` - Bot 1 container (production)
- `nanobot-user1-dev` - Bot 1 container (development)
- `nanobot-user2` - Bot 2 container
- `nanobot-user3` - Bot 3 container
### Ports
- User 1: `18790` (host) → `18790` (container)
- User 2: `18791` (host) → `18790` (container)
- User 3: `18792` (host) → `18790` (container)
### Config Locations
| Location | Used By | Purpose |
|----------|---------|---------|
| `~/.nanobot/config.json` | Host `nanobot gateway` | Original config (not used by Docker) |
| `~/.nanobot-user1/config.json` | Docker user1 | Bot 1 config (mounted into container) |
| `~/.nanobot-user2/config.json` | Docker user2 | Bot 2 config |
| `~/.nanobot-user3/config.json` | Docker user3 | Bot 3 config |
### Environment Files
| File | Loaded By | Purpose |
|------|-----------|---------|
| `.env.shared` | All Docker containers | Shared settings (API keys, model, etc.) |
| `.env.user1` | Docker user1 only | Bot 1 specific overrides |
| `.env.user2` | Docker user2 only | Bot 2 specific overrides |
| `.env.user3` | Docker user3 only | Bot 3 specific overrides |
| `.env` | Host `nanobot gateway` | Host environment (not used by Docker) |
### Quick Command Reference
```bash
# === START ===
docker compose -f docker-compose.multi.env.yml up -d nanobot-user1 # Start user1
docker compose -f docker-compose.multi.env.yml up -d # Start all
# === STOP ===
docker compose -f docker-compose.multi.env.yml stop nanobot-user1 # Stop user1
docker compose -f docker-compose.multi.env.yml down # Stop all
# === RESTART ===
docker compose -f docker-compose.multi.env.yml restart nanobot-user1 # Restart user1
docker compose -f docker-compose.multi.env.yml restart # Restart all
# === LOGS ===
docker logs -f nanobot-user1 # View logs
docker compose -f docker-compose.multi.env.yml logs -f nanobot-user1 # View logs
# === STATUS ===
docker compose -f docker-compose.multi.env.yml ps # List containers
docker ps | grep nanobot # List containers
# === REBUILD ===
docker compose -f docker-compose.multi.env.yml build nanobot-user1 # Rebuild user1
docker compose -f docker-compose.multi.env.yml build # Rebuild all
# === RECREATE (after config changes) ===
docker compose -f docker-compose.multi.env.yml up -d --force-recreate nanobot-user1
```
---
## Common Tasks
### Add a New Bot (User4)
1. Create config directory:
```bash
mkdir -p ~/.nanobot-user4
```
2. Create config file:
```bash
cat > ~/.nanobot-user4/config.json << 'EOF'
{
"channels": {
"telegram": {
"enabled": true,
"allowFrom": ["USERNAME"]
}
}
}
EOF
```
3. Create env file:
```bash
cp .env.user1 .env.user4
nano .env.user4 # Edit with bot-specific settings
```
4. Add to `docker-compose.multi.env.yml`:
```yaml
nanobot-user4:
# ... (copy from nanobot-user1, change port to 18793)
```
5. Start:
```bash
docker compose -f docker-compose.multi.env.yml up -d nanobot-user4
```
### Update Ollama API Base
If Ollama IP changes:
```bash
# Edit .env.shared
sed -i 's|http://172.17.0.1:11434|http://NEW_IP:11434|g' .env.shared
# Restart all containers
docker compose -f docker-compose.multi.env.yml restart
```
### Backup Configurations
```bash
# Backup all configs
tar -czf nanobot-configs-backup-$(date +%Y%m%d).tar.gz \
~/.nanobot-user* \
.env.shared .env.user*
# Restore
tar -xzf nanobot-configs-backup-YYYYMMDD.tar.gz
```
---
## Notes
- **Original config** (`~/.nanobot/config.json`) is NOT used by Docker containers
- **Host venv** is NOT needed to run Docker commands (Docker builds its own environment)
- **Environment variables** override config file settings
- **Arrays** (like `allowFrom`) must be in `config.json`, NOT in env files
- **Ollama API_BASE** must use `172.17.0.1` (Docker bridge) not `localhost`
---
## See Also
- `ENV_FILES_GUIDE.md` - Detailed env file management
- `DEVELOPMENT_WITH_DOCKER.md` - Development workflow details
- `SETUP_SUMMARY.md` - Initial setup summary
- `VERIFY_DOCKER_SETUP.md` - Verification checklist