mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
Both compose files are git-TRACKED, and Docker picks docker-compose.yaml over .yml — so the NAS reads the .yaml. The self-heal env (and prior changes) had only been committed to the .yml, leaving the tracked .yaml stale in the repo. Commit the .yaml so both carry the same config. Going forward: commit BOTH.
392 lines
16 KiB
YAML
392 lines
16 KiB
YAML
services:
|
|
# ==========================================================================
|
|
# PostgreSQL - Primary Database with pgvector for RAG
|
|
# ==========================================================================
|
|
postgres:
|
|
image: pgvector/pgvector:pg16
|
|
container_name: roboco-postgres
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_USER: roboco
|
|
POSTGRES_PASSWORD: roboco
|
|
POSTGRES_DB: roboco
|
|
ports:
|
|
- "15432:5432"
|
|
volumes:
|
|
- ${ROBOCO_DATA_DIR:-./data}/postgres:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U roboco -d roboco"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
|
|
# ==========================================================================
|
|
# Redis - Cache, Sessions, Event Bus
|
|
# ==========================================================================
|
|
redis:
|
|
image: redis:8-alpine
|
|
container_name: roboco-redis
|
|
restart: unless-stopped
|
|
command: redis-server --appendonly yes
|
|
ports:
|
|
- "16379:6379"
|
|
volumes:
|
|
- ${ROBOCO_DATA_DIR:-./data}/redis:/data
|
|
healthcheck:
|
|
test: ["CMD", "redis-cli", "ping"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
|
|
# ==========================================================================
|
|
# Ollama - Local LLM and Embedding Server
|
|
# ==========================================================================
|
|
ollama:
|
|
image: ollama/ollama:latest
|
|
container_name: roboco-ollama
|
|
restart: unless-stopped
|
|
environment:
|
|
OLLAMA_API_KEY: ${OLLAMA_API_KEY}
|
|
ports:
|
|
- "11435:11434"
|
|
volumes:
|
|
- ${ROBOCO_DATA_DIR:-./data}/ollama:/root/.ollama
|
|
healthcheck:
|
|
# Use ollama CLI (guaranteed available) to check if server is responding
|
|
test: ["CMD", "ollama", "list"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 10s
|
|
|
|
# Ollama model puller - pulls required models on startup
|
|
# Uses streaming curl to wait for full model download
|
|
ollama-init:
|
|
image: curlimages/curl:latest
|
|
container_name: roboco-ollama-init
|
|
depends_on:
|
|
ollama:
|
|
condition: service_healthy
|
|
restart: "no"
|
|
entrypoint: ["/bin/sh", "-c"]
|
|
command:
|
|
- |
|
|
set -e
|
|
echo "=== Pulling embedding model (qwen3-embedding:0.6b) ==="
|
|
# Ollama /api/pull streams JSON lines until complete - consume full stream
|
|
# Note: $$ escapes $ for docker-compose variable substitution
|
|
curl -sN http://ollama:11434/api/pull -d '{"name":"qwen3-embedding:0.6b"}' | while read -r line; do
|
|
status=$$(echo "$$line" | grep -o '"status":"[^"]*"' | cut -d'"' -f4)
|
|
[ -n "$$status" ] && echo " $$status"
|
|
done
|
|
echo "=== Pulling LLM model (glm-5:cloud) ==="
|
|
curl -sN http://ollama:11434/api/pull -d '{"name":"glm-5:cloud"}' | while read -r line; do
|
|
status=$$(echo "$$line" | grep -o '"status":"[^"]*"' | cut -d'"' -f4)
|
|
[ -n "$$status" ] && echo " $$status"
|
|
done
|
|
echo "=== Verifying models are available ==="
|
|
curl -sf http://ollama:11434/api/tags | grep -q "qwen3-embedding" && echo " qwen3-embedding: OK"
|
|
curl -sf http://ollama:11434/api/tags | grep -q "glm-5" && echo " glm-5: OK"
|
|
echo "=== All models ready! ==="
|
|
|
|
# ==========================================================================
|
|
# Agent Base Image Builder (specialized images built on-demand by orchestrator)
|
|
# ==========================================================================
|
|
agent-base-image:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/agent-base.Dockerfile
|
|
image: roboco-agent-base
|
|
container_name: roboco-agent-base-builder
|
|
entrypoint: ["/bin/sh", "-c", "echo 'Agent base image built successfully'"]
|
|
restart: "no"
|
|
|
|
# ==========================================================================
|
|
# Agent PM Image Builder (specialized image built on-demand by orchestrator)
|
|
# ==========================================================================
|
|
agent-pm-image:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/agent-pm.Dockerfile
|
|
image: roboco-agent-pm
|
|
entrypoint: ["/bin/sh", "-c", "echo 'Agent PM image built'"]
|
|
restart: "no"
|
|
depends_on:
|
|
- agent-base-image
|
|
|
|
# ==========================================================================
|
|
# Agent Backend Dev Image Builder (specialized image built on-demand by orchestrator)
|
|
# ==========================================================================
|
|
agent-dev-be-image:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/agent-dev-be.Dockerfile
|
|
image: roboco-agent-dev-be
|
|
entrypoint: ["/bin/sh", "-c", "echo 'Agent Backend Dev image built'"]
|
|
restart: "no"
|
|
depends_on:
|
|
- agent-base-image
|
|
|
|
# ==========================================================================
|
|
# Agent Frontend Dev Image Builder (specialized image built on-demand by orchestrator)
|
|
# ==========================================================================
|
|
agent-dev-fe-image:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/agent-dev-fe.Dockerfile
|
|
image: roboco-agent-dev-fe
|
|
entrypoint: ["/bin/sh", "-c", "echo 'Agent Frontend Dev image built'"]
|
|
restart: "no"
|
|
depends_on:
|
|
- agent-base-image
|
|
|
|
# ==========================================================================
|
|
# Agent Backend QA Image Builder (specialized image built on-demand by orchestrator)
|
|
# ==========================================================================
|
|
agent-qa-be-image:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/agent-qa-be.Dockerfile
|
|
image: roboco-agent-qa-be
|
|
entrypoint: ["/bin/sh", "-c", 'echo "Agent Backend QA image built"']
|
|
restart: "no"
|
|
depends_on:
|
|
- agent-base-image
|
|
|
|
# ==========================================================================
|
|
# Agent Frontend QA Image Builder (specialized image built on-demand by orchestrator)
|
|
# ==========================================================================
|
|
agent-qa-fe-image:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/agent-qa-fe.Dockerfile
|
|
image: roboco-agent-qa-fe
|
|
entrypoint: ["/bin/sh", "-c", 'echo "Agent Frontend QA image built"']
|
|
restart: "no"
|
|
depends_on:
|
|
- agent-base-image
|
|
|
|
# ==========================================================================
|
|
# Agent UX/UI Dev Image Builder (specialized image built on-demand by orchestrator)
|
|
# ==========================================================================
|
|
agent-ux-image:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/agent-ux.Dockerfile
|
|
image: roboco-agent-ux
|
|
entrypoint: ["/bin/sh", "-c", 'echo "Agent UX/UI image built"']
|
|
restart: "no"
|
|
depends_on:
|
|
- agent-base-image
|
|
|
|
# ==========================================================================
|
|
# Agent Documenter Image Builder (specialized image built on-demand by orchestrator)
|
|
# ==========================================================================
|
|
agent-doc-image:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/agent-doc.Dockerfile
|
|
image: roboco-agent-doc
|
|
entrypoint: ["/bin/sh", "-c", 'echo "Agent Documenter image built"']
|
|
restart: "no"
|
|
depends_on:
|
|
- agent-base-image
|
|
|
|
# ==========================================================================
|
|
# Agent Intake (Prompter) Image Builder (persistent Agent-SDK driver the CEO
|
|
# chats with; not a one-shot `claude -p`)
|
|
# ==========================================================================
|
|
agent-prompter-image:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/agent-prompter.Dockerfile
|
|
image: roboco-agent-prompter
|
|
entrypoint: ["/bin/sh", "-c", 'echo "Agent Intake image built"']
|
|
restart: "no"
|
|
depends_on:
|
|
- agent-base-image
|
|
|
|
agent-secretary-image:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/agent-secretary.Dockerfile
|
|
image: roboco-agent-secretary
|
|
entrypoint: ["/bin/sh", "-c", 'echo "Agent Secretary image built"']
|
|
restart: "no"
|
|
depends_on:
|
|
- agent-base-image
|
|
|
|
# ==========================================================================
|
|
# Agent PR Reviewer Image Builder (read-only reviewer of inbound external PRs)
|
|
# ==========================================================================
|
|
agent-pr-reviewer-image:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/agent-pr-reviewer.Dockerfile
|
|
image: roboco-agent-pr-reviewer
|
|
entrypoint: ["/bin/sh", "-c", 'echo "Agent PR Reviewer image built"']
|
|
restart: "no"
|
|
depends_on:
|
|
- agent-base-image
|
|
|
|
# ==========================================================================
|
|
# Orchestrator - API Server + Agent Spawner
|
|
# ==========================================================================
|
|
orchestrator:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/orchestrator.Dockerfile
|
|
image: roboco-orchestrator
|
|
container_name: roboco-orchestrator
|
|
restart: unless-stopped
|
|
ports:
|
|
- "8000:8000"
|
|
environment:
|
|
# Database (use container name, not localhost)
|
|
ROBOCO_DATABASE_HOST: roboco-postgres
|
|
ROBOCO_DATABASE_PORT: 5432
|
|
ROBOCO_DATABASE_USER: roboco
|
|
ROBOCO_DATABASE_PASSWORD: roboco
|
|
ROBOCO_DATABASE_NAME: roboco
|
|
# Redis (use container name)
|
|
ROBOCO_REDIS_HOST: roboco-redis
|
|
ROBOCO_REDIS_PORT: 6379
|
|
# API
|
|
ROBOCO_HOST: 0.0.0.0
|
|
ROBOCO_PORT: 8000
|
|
ROBOCO_ENCRYPTION_KEY: ${ROBOCO_ENCRYPTION_KEY:?ROBOCO_ENCRYPTION_KEY is required}
|
|
# HMAC secret for agent auth tokens. Orchestrator signs tokens
|
|
# per-agent at spawn; API middleware verifies them. Generate with:
|
|
# python -c 'import secrets; print(secrets.token_hex(32))'
|
|
ROBOCO_AGENT_AUTH_SECRET: ${ROBOCO_AGENT_AUTH_SECRET:?ROBOCO_AGENT_AUTH_SECRET is required}
|
|
# Set to "true" to require tokens on every API call (fail-closed).
|
|
# Leave unset/false during rollout so the panel + curl still work.
|
|
ROBOCO_AGENT_AUTH_REQUIRED: ${ROBOCO_AGENT_AUTH_REQUIRED:-false}
|
|
# Ollama (use container name)
|
|
ROBOCO_LOCAL_LLM_BASE_URL: http://roboco-ollama:11434/v1
|
|
ROBOCO_LOCAL_LLM_MODEL: glm-5:cloud
|
|
ROBOCO_DEFAULT_EMBEDDING_MODEL: qwen3-embedding:0.6b
|
|
ROBOCO_OLLAMA_BASE_URL: http://roboco-ollama:11434
|
|
# Host paths for spawning agent containers (required for Docker-in-Docker)
|
|
# IMPORTANT: These must be ABSOLUTE paths on the host filesystem
|
|
ROBOCO_HOST_PROJECT_DIR: ${ROBOCO_HOST_PROJECT_DIR:-/volume1/roboco}
|
|
ROBOCO_HOST_CLAUDE_DIR: ${ROBOCO_HOST_CLAUDE_DIR:-/home/renzof/.claude}
|
|
ROBOCO_HOST_DATA_DIR: ${ROBOCO_HOST_DATA_DIR:-/volume1/roboco/data}
|
|
# Public base URL for commit-trailer links. Default 127.0.0.1 produces
|
|
# unusable links in commit message bodies; set to NAS LAN IP so
|
|
# f"{api_base}/tasks/{task_id}" renders a reachable URL.
|
|
ROBOCO_PUBLIC_BASE_URL: "http://192.168.50.111:8000"
|
|
# Production environment selects structlog's JSONRenderer (machine-
|
|
# parseable logs) over the dev ConsoleRenderer.
|
|
ROBOCO_ENVIRONMENT: production
|
|
# Reaper timeouts raised to 30 min so a long agent task isn't reaped
|
|
# mid-work. ROBOCO_CLAIM_STALE_SECONDS is the heartbeat-staleness window
|
|
# _reap_stale_claims uses (the one that was killing in-progress work).
|
|
ROBOCO_CLAIM_STALE_SECONDS: "1800"
|
|
ROBOCO_STALE_CLAIM_REAP_SECONDS: "1800"
|
|
# External-PR review. When on, the org discovers inbound external/fork PRs
|
|
# and the PR reviewer posts one change-request — READ-ONLY (it never runs
|
|
# contributor code). The supersede that fetches + builds their code is
|
|
# separately CEO-triggered and stays gated by require_human_confirm.
|
|
# Override either via .env. (Config default is off; this enables it here.)
|
|
ROBOCO_EXTERNAL_PR_ENABLED: ${ROBOCO_EXTERNAL_PR_ENABLED:-true}
|
|
ROBOCO_EXTERNAL_PR_REQUIRE_HUMAN_CONFIRM: ${ROBOCO_EXTERNAL_PR_REQUIRE_HUMAN_CONFIRM:-true}
|
|
# ROBOCO_EXTERNAL_PR_POLL_INTERVAL_SECONDS: "300"
|
|
# ROBOCO_EXTERNAL_PR_AUTHOR_ALLOWLIST: '["corey"]' # empty = every external PR
|
|
# Production self-healing ("engine 4"). RoboCo watches its OWN repo CI and,
|
|
# when red, notifies the CEO and (with originate on) opens a PENDING fix
|
|
# task that STOPS for the CEO's Approve-&-Start — it never self-deploys.
|
|
# Both toggles default OFF (arm from Settings -> Feature Flags). Set
|
|
# PROJECT_SLUG to the registered project that IS RoboCo; CI_WORKFLOW scopes
|
|
# the signal to the real CI workflow (RoboCo has several workflows, so the
|
|
# unscoped "latest run" would be unreliable).
|
|
ROBOCO_SELF_HEAL_ENABLED: ${ROBOCO_SELF_HEAL_ENABLED:-false}
|
|
ROBOCO_SELF_HEAL_ORIGINATE_ENABLED: ${ROBOCO_SELF_HEAL_ORIGINATE_ENABLED:-false}
|
|
ROBOCO_SELF_HEAL_PROJECT_SLUG: ${ROBOCO_SELF_HEAL_PROJECT_SLUG:-roboco-api}
|
|
ROBOCO_SELF_HEAL_CI_WORKFLOW: ${ROBOCO_SELF_HEAL_CI_WORKFLOW:-ci.yml}
|
|
volumes:
|
|
# Docker socket - allows spawning agent containers
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
# Claude Code auth - mount your ~/.claude directory
|
|
- ${CLAUDE_AUTH_DIR:-/home/renzof/.claude}:/root/.claude
|
|
# Shared config directory for MCP configs (writable)
|
|
- ${ROBOCO_DATA_DIR:-./data}/mcp-configs:/app/mcp-configs
|
|
# Generated prompts directory - composed at runtime from layers
|
|
- ${ROBOCO_DATA_DIR:-./data}/prompts-generated:/app/prompts-generated
|
|
# Per-agent Claude settings (generated at spawn time)
|
|
- ${ROBOCO_DATA_DIR:-./data}/agent-settings:/app/agent-settings
|
|
# Agent workspaces (git clones) - persisted across restarts
|
|
- ${ROBOCO_DATA_DIR:-./data}/workspaces:/data/workspaces
|
|
# Persistent logs — survive `docker compose down/up`. Orchestrator and
|
|
# each spawned agent write structured logs here so we can audit past
|
|
# runs instead of relying on ephemeral `docker logs`.
|
|
- ${ROBOCO_DATA_DIR:-./data}/logs:/data/logs
|
|
# Per-agent SessionStart briefings (pre-rendered task context)
|
|
- ${ROBOCO_DATA_DIR:-./data}/briefings:/app/briefings
|
|
# Per-agent spawn manifests (role-scoped tool list) — written by the
|
|
# orchestrator to /app/manifests, bind-mounted into each agent container
|
|
# as /app/tool-manifest.json. Without this mount the file is written to
|
|
# the orchestrator's ephemeral fs, never reaches the host, and agents
|
|
# fall back to all-verbs registration.
|
|
- ${ROBOCO_DATA_DIR:-./data}/manifests:/app/manifests
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
ollama:
|
|
condition: service_healthy
|
|
ollama-init:
|
|
condition: service_completed_successfully
|
|
agent-base-image:
|
|
condition: service_completed_successfully
|
|
# Default agents to spawn (override in .env or command line)
|
|
# command: ["--spawn", "main-pm", "be-dev-1", "be-qa"]
|
|
|
|
# ==========================================================================
|
|
# Next.js Control Panel (Frontend)
|
|
# ==========================================================================
|
|
# Not exposed directly - nginx is the single entry point (port 3000).
|
|
# API/WS traffic is proxied to the orchestrator, everything else to panel.
|
|
panel:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/panel.Dockerfile
|
|
image: roboco-panel
|
|
container_name: roboco-panel
|
|
restart: unless-stopped
|
|
expose:
|
|
- "3000"
|
|
depends_on:
|
|
- orchestrator
|
|
|
|
# ==========================================================================
|
|
# Nginx - Reverse proxy fronting panel + orchestrator
|
|
# ==========================================================================
|
|
# Single entry point on port 3000 so the browser hits one origin and we
|
|
# don't need CORS. /api/* and /ws/* go to the orchestrator, everything
|
|
# else goes to the Next.js panel.
|
|
nginx:
|
|
image: nginx:alpine
|
|
container_name: roboco-nginx
|
|
restart: unless-stopped
|
|
ports:
|
|
- "3000:80"
|
|
environment:
|
|
# Rendered into the proxy config by the nginx image's envsubst
|
|
# entrypoint so the human panel authenticates in secure mode. The
|
|
# filter limits substitution to ROBOCO_* vars, leaving nginx's own
|
|
# $host / $remote_addr runtime variables untouched. Get the value
|
|
# with `make panel-token`.
|
|
ROBOCO_PANEL_AGENT_TOKEN: ${ROBOCO_PANEL_AGENT_TOKEN:-}
|
|
NGINX_ENVSUBST_FILTER: "^ROBOCO_"
|
|
volumes:
|
|
- ./docker/nginx.conf:/etc/nginx/templates/default.conf.template:ro
|
|
depends_on:
|
|
- panel
|
|
- orchestrator
|
|
|
|
networks:
|
|
default:
|
|
name: roboco_default
|