Skip to content

Docker

The Lota SDK provides a docker-compose.yml file that runs all required infrastructure services locally.

Quick Start

Get the SDK infrastructure running in three steps:

1. Install Docker

Install Docker Desktop for your platform. Ensure the Docker daemon is running.

2. Start services

bash
docker compose -f infrastructure/docker-compose.yml up -d

3. Verify

bash
# Check all containers are running
docker compose -f infrastructure/docker-compose.yml ps

# Test SurrealDB
curl -s http://localhost:8003/health

# Test Redis
redis-cli -p 6382 ping
# Expected: PONG

# Test Bifrost
curl -s http://localhost:8081/health

SurrealDB, Redis, and Bifrost should report healthy status. Qdrant runs as an internal service with no host port exposure. You can now configure the SDK runtime to connect to the stack (see Corresponding SDK Configuration below).

Services

The compose file at infrastructure/docker-compose.yml defines four services:

SurrealDB

The primary database for workstreams, messages, memory, execution plans, and all persistent state.

SettingValue
Imagesurrealdb/surrealdb:v3.0.3
Port8003:8000
StorageRocksDB at /data/database.db
Volumesurrealdb_data

Default credentials:

  • Username: root
  • Password: root

Override with environment variables SURREALDB_USER and SURREALDB_PASSWORD.

Redis

Used for BullMQ job queues and distributed memory locks.

SettingValue
Imageredis:8.6-alpine
Port6382:6379
PersistenceAOF (append-only file)
Volumeredis_data

Bifrost (AI Gateway)

The AI gateway that all LLM requests route through.

SettingValue
Imagemaximhq/bifrost:latest
Port8081:8080
Health checkhttp://localhost:8080/health
Configinfrastructure/bifrost.config.json mounted read-only at /app/data/config.json
State volumenamed gateway_data volume for SQLite config/log state

Environment variables:

  • APP_PORT=8080
  • APP_HOST=0.0.0.0
  • LOG_LEVEL=info
  • LOG_STYLE=json
  • ../.env is loaded for AI_GATEWAY_KEY, AI_GATEWAY_ADMIN, AI_GATEWAY_PASS, AI_GATEWAY_QDRANT_KEY, and upstream provider keys

Qdrant

Internal vector store service kept alongside the gateway for future use.

SettingValue
Imageqdrant/qdrant:v1.17.0
Host portnone
Internal gRPC port6334
Volumeqdrant_data
AuthAI_GATEWAY_QDRANT_KEY passed to both Qdrant and Bifrost

Starting Services

bash
cd infrastructure
docker compose up -d

Or from the project root:

bash
docker compose -f infrastructure/docker-compose.yml up -d

Stopping Services

bash
docker compose -f infrastructure/docker-compose.yml down

To also remove volumes (deletes all data):

bash
docker compose -f infrastructure/docker-compose.yml down -v

Port Configuration

Default port mappings:

ServiceContainer PortHost Port
SurrealDB80008003
Redis63796382
Bifrost80808081

Corresponding SDK Configuration

Map Docker ports to LotaRuntimeConfig:

ts
const runtime = await createLotaRuntime({
  database: {
    url: 'ws://localhost:8003/rpc',
    namespace: 'lota',
    username: 'root',
    password: 'root',
  },
  redis: {
    url: 'redis://localhost:6382',
  },
  aiGateway: {
    url: 'http://localhost:8081',
    key: 'sk-bf-your-virtual-key',
  },
  // ...
})

Verifying Services

After starting the stack, verify each service is running and healthy.

Check all containers

bash
docker compose -f infrastructure/docker-compose.yml ps

SurrealDB, Redis, and Bifrost should show Up status. Bifrost should also show (healthy) once its health check passes.

SurrealDB

bash
curl -s http://localhost:8003/health

A 200 OK response confirms SurrealDB is accepting connections. You can also test a query:

bash
curl -s -X POST http://localhost:8003/sql \
  -H "Accept: application/json" \
  -H "NS: lota" \
  -H "DB: lotasdk" \
  -u "root:root" \
  --data "INFO FOR DB"

Redis

bash
redis-cli -p 6382 ping

Expected response: PONG. To check memory usage:

bash
redis-cli -p 6382 info memory | head -5

Bifrost

bash
curl -s http://localhost:8081/health

A 200 OK response confirms the gateway is running. Bifrost also has a built-in Docker health check that runs every 30 seconds.

Health Checks

SurrealDB

SurrealDB does not expose a dedicated health endpoint in the compose file. The SDK uses connectWithStartupRetry() to poll for readiness:

ts
await connectWithStartupRetry({
  connect: () => runtime.connect(),
  label: 'SurrealDB',
  maxWaitMs: 180_000,
})

Redis

Redis readiness is checked through ioredis connection events. The RedisConnectionManager runs periodic health checks (default: every 30 seconds) using PING.

Bifrost

Bifrost includes a health check configuration:

  • Endpoint: http://localhost:8080/health
  • Interval: 30 seconds
  • Timeout: 10 seconds
  • Retries: 3

Volumes

VolumeServicePurpose
qdrant_dataQdrantSemantic cache vector storage
surrealdb_dataSurrealDBDatabase files (RocksDB)
redis_dataRedisAOF persistence
infrastructure/bifrost.config.jsonBifrostTracked gateway bootstrap config
gateway_dataBifrostSQLite config/log state after bootstrap

Troubleshooting

Port conflicts

If a service fails to start with a "port already in use" error, another process is occupying the host port.

bash
# Find what is using port 8003 (SurrealDB)
lsof -i :8003

# Find what is using port 6382 (Redis)
lsof -i :6382

# Find what is using port 8081 (Bifrost)
lsof -i :8081

Stop the conflicting process, or change the host port mapping in docker-compose.yml. For example, to move SurrealDB to port 8004:

yaml
ports:
  - "8004:8000"

Then update your SDK config to use ws://localhost:8004/rpc.

Volume permission issues

If SurrealDB or Redis fail with permission errors on their data volumes:

bash
# Remove volumes and recreate
docker compose -f infrastructure/docker-compose.yml down -v
docker compose -f infrastructure/docker-compose.yml up -d

On Linux, you may need to ensure the Docker user has write access to the volume mount paths. Named volumes (used by SurrealDB and Redis) are managed by Docker and rarely have permission issues. The .gateway-data bind mount for Bifrost is created automatically.

Bifrost not starting

Bifrost requires environment variables for API keys. If Bifrost exits immediately or shows unhealthy status:

  1. Check that ../.env exists relative to the infrastructure/ directory (i.e., .env at the project root).
  2. Ensure the following variables are set in .env:
    • AI_GATEWAY_KEY -- The virtual key for SDK requests
    • AI_GATEWAY_ADMIN -- Admin username for Bifrost
    • AI_GATEWAY_PASS -- Admin password for Bifrost
    • At least one upstream provider key (e.g., ANTHROPIC_API_KEY, OPENAI_API_KEY)
  3. Check Bifrost logs:
bash
docker compose -f infrastructure/docker-compose.yml logs bifrost
  1. Verify infrastructure/bifrost.config.json exists and is valid JSON.

SurrealDB connection refused

If the SDK cannot connect to SurrealDB after docker compose up:

  1. Container not running: Check docker compose ps to see if the container exited.
  2. Still starting up: SurrealDB may take a few seconds to initialize. The SDK's connectWithStartupRetry() handles this with retries up to 180 seconds.
  3. Wrong URL: Ensure you are using ws://localhost:8003/rpc (not port 8000, which is the container-internal port).
  4. Authentication failure: Verify credentials match between docker-compose.yml and your SDK config. Default is root/root.
bash
# Check SurrealDB container logs
docker compose -f infrastructure/docker-compose.yml logs surrealdb

Redis connection issues

If workers fail to start or queues are not processing:

bash
# Check Redis container status
docker compose -f infrastructure/docker-compose.yml logs redis

# Test connectivity
redis-cli -p 6382 ping

Ensure your SDK config uses redis://localhost:6382 (not port 6379).

Production Considerations

The provided Docker Compose setup is intended for local development. For production deployments, address the following.

Credentials

Do not use the default root/root credentials for SurrealDB in production. Set strong passwords:

bash
export SURREALDB_USER=your_secure_username
export SURREALDB_PASSWORD=your_secure_password

Similarly, set strong values for AI_GATEWAY_ADMIN, AI_GATEWAY_PASS, and AI_GATEWAY_KEY in your production environment.

Redis persistence and memory

The development setup uses AOF (append-only file) persistence. For production:

  • Enable both AOF and RDB snapshots for durability.
  • Set a maxmemory limit and an appropriate eviction policy. BullMQ requires noeviction to prevent job data loss:
    maxmemory 2gb
    maxmemory-policy noeviction
  • Consider Redis Sentinel or Redis Cluster for high availability.
  • Enable Redis AUTH with a strong password.

SurrealDB storage

The development setup uses RocksDB with a Docker volume. For production:

  • Back up the surrealdb_data volume regularly.
  • Monitor disk usage -- RocksDB storage grows with data and compaction.
  • Consider running SurrealDB on dedicated infrastructure with SSD storage for better I/O performance.

Bifrost configuration

For production AI gateway deployments:

  • Use dedicated API keys per environment.
  • Configure rate limiting and cost controls in bifrost.config.json.
  • Set LOG_LEVEL=warn or LOG_LEVEL=error to reduce log volume.
  • Monitor the .gateway-data SQLite state for request logs and analytics.

Volume backup strategies

For Docker volume backups:

bash
# Backup SurrealDB data
docker run --rm -v surrealdb_data:/data -v $(pwd)/backups:/backup \
  alpine tar czf /backup/surrealdb-$(date +%Y%m%d).tar.gz -C /data .

# Backup Redis data
docker run --rm -v redis_data:/data -v $(pwd)/backups:/backup \
  alpine tar czf /backup/redis-$(date +%Y%m%d).tar.gz -C /data .

Schedule these as cron jobs or use your infrastructure provider's snapshot capabilities. For Redis, trigger a BGSAVE before backing up to ensure a consistent snapshot.

Network security

In production, do not expose database and Redis ports to the public internet. Use:

  • Internal Docker networks or private subnets.
  • Bind host ports to 127.0.0.1 only if services run on the same host as the application:
    yaml
    ports:
      - "127.0.0.1:8003:8000"
      - "127.0.0.1:6382:6379"
  • TLS for SurrealDB WebSocket connections and Redis connections where supported.