# Matrix intake bot Turns a typed message in a dedicated Matrix room into a proposed fundraising-grid add/edit, gated on in-thread human approval before any write. Runs as its own process (on the Spark), separate from the CRM. Full design + rules: `docs/guides/matrix-intake.md`. ## Run ```bash # 1. Install the one third-party dep (isolated to this component — NOT the CRM runtime) python3 -m pip install -r requirements.txt # matrix-nio # 2. Fill the MATRIX_* and CRM_BOT_* vars in the repo .env (see ../../.env.example), # and create a dedicated CRM user for CRM_BOT_USERNAME/PASSWORD (admin → invite user). # 3. Start the listener python3 bot.py ``` It primes the Matrix sync past history (no backlog replay), then listens. Post a message in the intake room; it replies in a thread with the parsed proposal. Reply **yes** to commit, **edit field=value** to change a field, or **no** to discard. ## Layout - `bot.py` — entrypoint: connect, prime-then-listen, dispatch (lifts matrix-bridge's plumbing). - `parse.py` — message → structured proposal via local Qwen (`spark.py` → `backend/ingest/llm.py`). - `proposals.py` — in-memory pending-proposal store + the yes/edit/no state machine. - `crm_client.py` — login + `GET /api/intake/match` + write via `POST /api/fundraising/log-communication`. - `matrix_io.py` — message splitting, thread-root detection, threaded-reply sender. - `settings.py` — Matrix + CRM-API config (named `settings`, not `config`, to avoid shadowing `ingest/config`). ## Test (offline) ```bash python3 test_parse.py && python3 test_proposals.py && python3 test_crm_client.py # endpoint + create→match contract (boots the real server against a temp DB): cd ../ && python3 test_intake_endpoints.py ``` Live Matrix behavior needs creds + `matrix-nio` and can only be smoke-tested on the Spark.