Refresh of the open-core distribution from the private tree. Included since the previous snapshot: - Mail module (ADR-158/159/160/169): composer, labels, scheduling, attachments, reply-tokens, IMAP/SMTP bridge + migrations 079-083 - Crawler-readable SSR for /blog and public spaces (ADR-190): blogSeo, publicDocsSeo, per-space SEO prefs, blog index/post pages - Registration policy + referral/promo settings (ADR-183/188) - Message translation + language detection (ADR-185) - Reddit connector for the agent-tool surface Excised from the public distribution (unchanged policy): infrastructure topology and host config, internal ops scripts, DB cleanup snapshots, business documents, throwaway debug scripts, and two private product lines (SC-SIM simulator, personal one-off tools). Real host addresses are replaced with placeholders; credential-shaped literals are redacted. Frontend build verified green on this tree. |
||
|---|---|---|
| .. | ||
| docker-compose.yml | ||
| docker-entrypoint.sh | ||
| Dockerfile | ||
| env.example | ||
| install.sh | ||
| README.md | ||
| schema.sql | ||
GOD CRM — Self-Host
Run the whole CRM on your own box with one command. The core is MIT — clone it, run it, your data stays in a shape you can read.
Quick start
cd deploy/selfhost
./install.sh
The installer generates secrets, asks where agent memory should live, then builds and starts everything. When it finishes, open http://localhost:5000 — the first account you register becomes the owner.
Manual start (no installer)
cd deploy/selfhost
cp env.example .env
# generate secrets and fill the empty values in .env:
# openssl rand -hex 32 # JWT_SECRET, ENCRYPTION_KEY, ... and CRM_CREDENTIAL_KEY
# openssl rand -hex 24 # POSTGRES_PASSWORD, HINDSIGHT_DB_PASSWORD
# openssl rand -base64 32 # SECRETS_MASTER_KEY
docker compose up -d --build
What you get
| Service | Image | Notes |
|---|---|---|
app |
built from this repo | Express API + built React frontend on port 5000 |
db |
pgvector/pgvector:pg16 |
the CRM database; schema is migrated automatically on boot |
pgvector/pgvector:pg16 is stock Postgres 16 with the vector extension
available. It is the default in every mode so that turning memory on later
never means swapping the image under an existing data volume.
Data lives in named volumes (godcrm-db, godcrm-uploads) — it survives
docker compose down and is removed only with docker compose down -v.
Optional: agent memory (RCLL)
Long-term memory shared by your agents. Off by default. There are three placements of the same store — not three feature tiers. Same image, same migrations, same data model:
MEMORY_MODE |
Where memory lives | Trade-off |
|---|---|---|
none |
nowhere | leanest install; memory tools are inert |
embedded |
schema MEMORY_SCHEMA inside the CRM database |
one database to run and back up; memory migrations are DDL against your CRM database |
standalone |
its own database, container and volume | two databases to back up; the CRM database is never touched by memory DDL |
docker compose --profile memory-embedded up -d
docker compose --profile memory-standalone up -d
Enable exactly one. Both answer on the same network alias (hindsight), so
HINDSIGHT_URL is identical either way.
Switching mode later does not move the data — dump from the old placement and load into the new one.
Things worth knowing before you pick
- The read path never calls an LLM. Embeddings and reranker run locally on
CPU. A model is used only to classify memories on write;
LLM_PROVIDER=noneis fully supported — writes and recall still work, only automatic classification is off. A real provider with an empty key does not degrade, it fails to boot, so the installer writesnonewhen you have no key. embeddedruns memory migrations against your CRM database. A fresh install needs that once, to build the schema. After first boot setMEMORY_RUN_MIGRATIONS=falsein.envand run upgrades deliberately, after a backup.- The memory image is large (~6 GB) and pulls on first start.
Configuration
All settings live in .env (template: env.example). The two you'll most
likely change:
PUBLIC_URL— the origin you open the app from. It must match, or the browser gets a white screen (CORS gates the static assets). For a domain set e.g.PUBLIC_URL=https://crm.example.comand front the app with your own TLS-terminating reverse proxy →http://localhost:${APP_PORT}.APP_PORT— host port (default5000).MEMORY_MODE—none/embedded/standalone, see above.
Your shell wins over
.env. Compose resolves${VAR}from the shell environment first. If your shell already exportsPOSTGRES_*orJWT_SECRET— a box that runs another app, a sourced profile — the stack silently uses those instead of.env: wrong database, wrong secret, no error.install.shchecks for this and stops; if you start compose by hand, run it from a clean shell.
Common commands
docker compose logs -f app # follow app logs
docker compose ps # status
docker compose down # stop (keeps data)
docker compose down -v # stop and delete all data volumes
docker compose up -d --build # rebuild after pulling new code