OpenOutreach runs as a single browserless daemon — a slim Python image with no browser and no VNC. All you interact with is the terminal (for onboarding) and, optionally, the Django Admin.
Pre-built images are published to GitHub Container Registry.
docker run --pull always -it -v ~/.openoutreach/data:/app/data ghcr.io/eracle/openoutreach:latest-itis required so the interactive onboarding can prompt you on first run — product/objective → LLM key → mailbox (paste an app password) → BetterContact key → your email → country → newsletter/legal.-v ~/.openoutreach/data:/app/datapersists everything (CRM database, model blobs, embeddings) on your host across restarts.
There are no ports to publish — the daemon has no web server of its own and no browser to watch. (To browse your CRM, run the Django Admin separately; see below.)
| Tag | Description |
|---|---|
latest |
Latest published build |
sha-<commit> |
Pinned to a specific commit |
1.0.0 / 1.0 |
Semantic version (when tagged) |
# Find the container
docker ps
# Stop it
docker stop <container-id>
# Restart (data persists in the mounted directory)
docker run --pull always -it -v ~/.openoutreach/data:/app/data ghcr.io/eracle/openoutreach:latestThe daemon image runs the worker, not a web server. To browse Leads and Deals, run the admin server (locally or in a second container) and publish port 8000:
docker run --pull always -it -p 8000:8000 -v ~/.openoutreach/data:/app/data \
ghcr.io/eracle/openoutreach:latest python manage.py runserver 0.0.0.0:8000Then open http://localhost:8000/admin/ (create a superuser first with python manage.py createsuperuser).
For development or customization, you can build the image locally. The compose file (local.yml)
mounts the entire project directory into the container for live code editing.
git clone https://github.com/eracle/OpenOutreach.git
cd OpenOutreach
# Build and start
make upThis builds the Docker image from source with BUILD_ENV=local (includes test dependencies) and starts the daemon.
Note: The compose file uses HOST_UID / HOST_GID environment variables (defaulting to 1000)
for file ownership. If your host UID differs from 1000, set them explicitly:
HOST_UID=$(id -u) HOST_GID=$(id -g) make up| Command | Description |
|---|---|
make build |
Build the Docker image without starting |
make up |
Build and start the daemon |
make stop |
Stop the running containers |
make logs |
Follow application logs |
make docker-test |
Run the test suite in Docker |
The pre-built docker run command mounts a host directory at /app/data for persistence (database, config). The compose setup (local.yml) mounts the entire repo .:/app for live code editing during development.
To run against a database file you already have, bind-mount the host directory containing it onto /app/data (the app opens /app/data/db.sqlite3):
docker run --pull always -it -v ~/.openoutreach/data:/app/data ghcr.io/eracle/openoutreach:latestPlace your db.sqlite3 inside the mounted directory (~/.openoutreach/data/ above; swap for your own path). Two caveats: the dir and file must be writable by uid 1000 (the container user) or writes fail with readonly database; and rundaemon runs migrate on startup, so back the file up first (cp db.sqlite3{,.bak}) if it's precious.