# Ten31 agentic system — environment template. # Copy to .env (gitignored) and fill in. Secret values NEVER go in .env.example. # ── Claude (frontier reasoning; Agent SDK uses an API key, not claude.ai login) ── ANTHROPIC_API_KEY= # ── Spark Control gateway (local model services; reads + dense embeds) ── # HTTPS with the Start9 self-signed cert -> clients must skip TLS verification. SPARK_CONTROL_URL=https://: SPARK_CONTROL_VERIFY_TLS=false # ── Qdrant (direct, for ingest: create collection + upsert points) ── # Plain HTTP on the trusted LAN, no auth currently. QDRANT_URL=http://:6333 # ── X (Twitter) API for Scout/Analyst enrichment (NOT a CRM key) ── X_API_KEY= # ── CRM (ingest opens the SQLite file directly, read-only) ── CRM_DB_PATH=./data/crm.db CRM_DEV_DB_PATH=./data/crm_dev.db # ── Daily activity digest (Phase B) ── # The daily digest (each team member's activity per investor + a by-investor view, # summarized LOCALLY on Spark — never Claude) is controlled from Settings → Admin # (stored in the DB). These env vars only SEED the first-boot default before an # admin sets it; once the policy row exists, the admin panel wins. The "Send Digest # Now" button works regardless. Leave blank to default to off / 6 PM. CRM_DIGEST_ENABLED= # Local (box-time) hour 0-23. Default 18 (6 PM). CRM_DIGEST_SEND_HOUR=18 # ── Daily-digest sender ── # The digest mailer prefers Gmail domain-wide delegation (the service account that # already powers email capture; its grant includes gmail.compose, which can send) and # falls back to SMTP below. For the Gmail/DWD path it sends impersonating this domain # user; if unset, it uses the first active admin's email. CRM_DIGEST_SENDER= # ── Daily-digest outbound SMTP fallback (dev override of the per-package mailbox) ── # On the Start9 box these are set by the "Configure Digest SMTP" action (written # to /data/secrets/smtp/* and exported by docker_entrypoint.sh). For dev, set them # here. SMTP_SECURITY is one of: starttls (587) | tls (465) | none. SMTP_HOST= SMTP_PORT=587 SMTP_SECURITY=starttls SMTP_FROM= SMTP_USERNAME= SMTP_PASSWORD= # ── Matrix intake bot (backend/matrix_intake/, runs as its own process on the Spark) ── # Parses a typed message in a dedicated Matrix room into a proposed fundraising-grid # add/edit (local Qwen via Spark Control above), then writes through the CRM API only # after in-thread human approval. Reuses SPARK_CONTROL_URL / CRM_CHAT_MODEL above. MATRIX_HOMESERVER=https:// MATRIX_USER=@intake-bot: MATRIX_ACCESS_TOKEN= MATRIX_DEVICE_ID=ten31-intake-bot MATRIX_INTAKE_ROOM=!: # Dedicated room for reviewing CRM-drafted email-activity proposals (the proposed grid notes the # Email Capture panel shows). The bot posts a review card per pending proposal here and relays the # in-thread yes/no/edit back to the CRM, in sync with the web panel. Separate from the intake room # so high-volume email proposals don't drown the conversational intake. Leave empty to disable the # whole email-review poll loop. The bot must be a member of this room. Needs the server side in the # s9pk (≥ v0.1.0:89) and the bot's CRM user set to role 'bot' (see docs/guides/matrix-intake.md). MATRIX_EMAIL_REVIEW_ROOM=!: # CRM write-back: the bot logs in as a DEDICATED service user (admin-created CRM user; # the CRM has no service-key path, so it uses normal Bearer-JWT auth). CRM_API_BASE=http://127.0.0.1:8080 CRM_BOT_USERNAME= CRM_BOT_PASSWORD= # Set to false only if CRM_API_BASE is https with a self-signed cert. CRM_API_VERIFY_TLS=true # Ten31 team-member names (comma-separated), fed to the parser so a teammate's name reads as # the person DOING outreach, not the prospect ("Jonathan is chatting with Wyoming" → Wyoming). # Optional; first names as actually used in the room. Leave empty to disable the framing. INTAKE_TEAM_ROSTER=