PlanExe uses Docker
Docker is the supported way to run PlanExe locally and in most deployments. This page covers common Docker workflows and troubleshooting.
Basic lifecycle
- Stop everything:
docker compose down - Build fresh (no cache) after code moves:
docker compose build --no-cache database_postgres worker_plan frontend_multi_user - Start services:
docker compose up - Stop services (leave images):
docker compose down - Build fresh and start services:
docker compose build --no-cache database_postgres worker_plan frontend_multi_user && docker compose up
While developing
Simons typical workflow.
While making code changes, I use ./rebuild.sh, that does this:
Frequently I do docker system prune -a to free disk space.
- Live rebuild/restart on changes:
docker compose watch(requires Docker Desktop 4.28+).
If watch misses changes after file moves, rerun the no-cache build above. - View logs:
docker compose logs -f worker_plandocker compose logs -f frontend_multi_user
Run individual files
- Rebuild the worker image when code or data files change:
docker compose build --no-cache worker_plan. - Run a one-off module inside the worker image (same deps/env as the API):
docker compose run --rm worker_plan python -m worker_plan_internal.fiction.fiction_writer(swap the module path as needed). If containers are already up, usedocker compose exec worker_plan python -m ...instead. - For host Ollama access, set
base_urlinllm_config/<profile>.jsontohttp://host.docker.internal:11434(default Ollama port). On Linux, addextra_hosts: ["host.docker.internal:host-gateway"]underworker_planif that hostname is missing, or use your bridge IP. - Ensure required env vars (e.g.,
DEFAULT_LLM) are available via.envor your shell before running the command.
Troubleshooting
- If the pipeline stops immediately with missing module errors, rebuild with
--no-cacheso new files are inside the images. - If you change environment variables (e.g.,
PLANEXE_WORKER_RELAY_PROCESS_OUTPUT), restart:docker compose downthendocker compose up. - If
frontend_multi_usercan't start because host port 5000 is busy, map it elsewhere:export PLANEXE_FRONTEND_MULTIUSER_PORT=5001(or another free port) beforedocker compose up. - To clean out containers, network, and orphans:
docker compose down --remove-orphans. - To reclaim disk space when builds start failing with
No space left on device: - See current usage:
docker system df - Aggressively prune (images, caches, networks not in use):
docker system prune -a- Expect a confirmation prompt; this removed ~37 GB here by deleting unused images and build cache.
- If needed, prune build cache separately:
docker builder prune
Port 5432 already in use (Postgres conflict)
If database_postgres fails to start with a "port already in use" error, another PostgreSQL is likely running on your machine. This is common on developer machines where you have:
- macOS: Postgres.app (a popular menu-bar Postgres), Homebrew PostgreSQL (brew install postgresql), or pgAdmin's bundled server
- Linux: System PostgreSQL installed via apt install postgresql or similar
- Windows: PostgreSQL installer, pgAdmin, or other database tools
Solution: Set PLANEXE_POSTGRES_PORT to a different value:
This only affects the HOST port (how you access Postgres from your machine). Inside Docker, containers always connect to each other on port 5432—this is hardcoded and unaffected by PLANEXE_POSTGRES_PORT.
To make this permanent, add to your .env file:
When connecting from your host machine (e.g., DBeaver, psql), use the port you set:
Environment notes
- The worker exports logs to stdout when
PLANEXE_WORKER_RELAY_PROCESS_OUTPUT=true(set indocker-compose.yml). - Shared volumes:
.envand./llm_config/are mounted read-only. Ensure they exist on the host before starting. - Database: Postgres runs in
database_postgresand listens on host${PLANEXE_POSTGRES_PORT:-5432}mapped to container5432; data is persisted in the named volumedatabase_postgres_data. - Multiuser UI: binds to container port
5000, exposed on host${PLANEXE_FRONTEND_MULTIUSER_PORT:-5001}. - MCP server downloads: set
PLANEXE_MCP_PUBLIC_BASE_URLso clients receive a reachable/download/...URL (defaults tohttp://localhost:8001in compose).