Sets up everything needed to deploy behind Cloudflare with a self-hosted git server: multi-stage prod Dockerfiles (non-root), docker-compose.prod.yml (Postgres/Redis with no host ports, Nginx reverse proxy, Gitea with public-read/admin-write access control), scripts/bootstrap-env.sh to auto-generate required secrets on first clone, and DEPLOYMENT.md covering the full runbook. Provider API keys (Anthropic/Brave/NinjaPear/USPTO/ Turnstile) are deliberately kept out of .env in favor of the existing DB-backed Settings UI, so the public repo stays safe to expose. Also fixes two bugs only surfaced by live-testing the prod stack: Celery beat couldn't write its schedule file as a non-root user, and Gitea's embedded SSH server conflicted with the base image's own sshd on port 22. Co-Authored-By: Claude Sonnet 5 <[email protected]>
CI Agent — Competitive Intelligence Monitoring
CI Agent monitors companies you choose, collects publicly available information from multiple sources on a schedule, analyzes it with an LLM into an evidence-linked report, detects meaningful changes between runs, and alerts you by email (and optionally SMS) with a severity and confidence score.
See PLAN.md for the build strategy, ARCHITECTURE.md for system design, SECURITY.md for the threat model, TASKS.md for the live implementation checklist, KNOWN_LIMITATIONS.md for what's stubbed vs. fully live, and docs/FIREBASE_MIGRATION.md for a (skeptical) look at what moving to Firebase would take.
Quick start (Docker)
git clone <repository>
cd ci-agent
cp .env.example .env
docker compose up --build
Then visit:
| Service | URL |
|---|---|
| Frontend | http://localhost:3000 |
| Backend API | http://localhost:8000 |
| API docs (Swagger) | http://localhost:8000/docs |
The default .env.example runs in AUTH_MODE=local (no login required, fixed dev user) with LLM_PROVIDER=mock and SEARCH_PROVIDER=mock — the whole demo workflow works with zero paid API keys.
api, worker, and beat build from the same Dockerfile but are separate images — after adding a Python dependency, run docker compose build api worker beat (not just restart) or they'll crash with ModuleNotFoundError on stale images.
Similarly, after adding an npm dependency to apps/web, a plain rebuild isn't enough either — web's node_modules and .next are both persistent anonymous Docker volumes that survive docker compose build web and even a plain docker compose restart web. This means a new package can still 404, and — on Windows + Docker Desktop — an edited existing file can keep serving its pre-edit output after a restart, since the on-disk .next build cache isn't cleared by a restart. Run docker compose rm -f -s -v web && docker compose up -d web to actually pick up new packages or force a clean recompile.
Running without Docker
Backend:
cd apps/api
python -m venv .venv
./.venv/Scripts/activate # or `source .venv/bin/activate` on macOS/Linux
pip install -e ".[dev]"
cp ../../.env.example ../../.env # edit DATABASE_URL to the sqlite line if you don't have Postgres running
alembic upgrade head
uvicorn app.main:app --reload
Frontend:
cd apps/web
npm install
npm run dev
Common commands
# Database migrations
cd apps/api && alembic upgrade head
cd apps/api && alembic revision --autogenerate -m "description"
# Run a Celery worker + beat (only needed outside Docker)
cd apps/api && celery -A app.tasks.celery_app worker --loglevel=INFO -Q default,collection,analysis,notifications,maintenance
cd apps/api && celery -A app.tasks.celery_app beat --loglevel=INFO
# Backend tests / lint / format
cd apps/api && pytest
cd apps/api && ruff check app tests
cd apps/api && black app tests
# Frontend tests / lint / format / typecheck
cd apps/web && npm test
cd apps/web && npm run lint
cd apps/web && npm run format
cd apps/web && npm run typecheck
# End-to-end test (requires `docker compose up -d` already running)
cd apps/web && npx playwright install --with-deps chromium # one-time
cd apps/web && npm run e2e
Configuration
All configuration is via environment variables — see .env.example for the full list with comments. Highlights:
AUTH_MODE=local|jwt— local single-user dev mode vs. real email/password accounts.LLM_PROVIDER=mock|anthropic|ollama|gemini— setANTHROPIC_API_KEY/ANTHROPIC_MODEL,OLLAMA_BASE_URL/OLLAMA_MODEL, orGEMINI_API_KEY/GEMINI_MODELto go live. Gemini has a genuine free tier — grab a key at aistudio.google.com/apikey — so it's the cheapest provider to actually try against a real model.SEARCH_PROVIDER=mock|brave— setBRAVE_SEARCH_API_KEYto go live.SMTP_HOST/RESEND_API_KEY— no bundled local mail sink; point SMTP at a real relay or setRESEND_API_KEYto actually test email delivery (alerts and security email both use this).NOTIFICATION_SMS_ENABLED=falseby default — set totrueand provideTWILIO_*to enable SMS.
Every paid/external provider defaults to a mock/console implementation. Automated tests always run against mocks and never call a paid API.
Known limitations
See KNOWN_LIMITATIONS.md.