Was always blank by default. Now prefilled from useCurrentUser() once it loads (defaultValues can't do this since the query resolves after mount), gated on the field not being dirty yet so it never clobbers something the user already typed - still fully editable either way. 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.