v0.9 Platform Multi-Customer

OpenClaw Email Bot — Platform Design Document

An AI-powered email response platform for professional services. Monitors shared mailboxes via Microsoft Graph, processes enquiries through a configurable pipeline, and generates contextual replies using Anthropic Claude — with full audit trail, escalation routing, and a real-time monitoring dashboard.

Pipeline Steps
9
Fully configurable
LLM Models
3
Opus, Sonnet, Haiku
KB Backends
2
LanceDB + BM25
Escalation Types
2
Domain Expert + Admin
Sender Modes
3
Auto, Command, Conversational
Deploy
2-Phase
Code + customer data

1. Platform Overview

OpenClaw Email Bot is a self-hosted, AI-powered email response platform designed for small-to-medium professional services businesses. It monitors a shared mailbox, understands incoming enquiries using a curated knowledge base, generates contextual replies via Anthropic’s Claude models, and routes sensitive or complex matters to human reviewers.

Target verticals: Healthcare clinics, legal practices, accounting firms, consultancies — any organisation that handles a high volume of repetitive enquiries with domain-specific knowledge requirements.

Core value proposition:

  • Domain-aware responses — Semantic knowledge base search ensures replies are grounded in your organisation’s actual policies, pricing, and procedures
  • Safety-first design — Draft mode, input/output guardrails, escalation routing, and full audit trail ensure no reply reaches a customer without appropriate oversight
  • Admin via email — Trusted senders can update knowledge base documents, modify core behaviour, and manage the system entirely through email commands
  • Multi-customer architecture — Each customer deployment is fully isolated with its own config, knowledge base, branding, and runtime data
  • Real-time monitoring — Web dashboard with health status, KPIs, charts, and activity logs

2. System Architecture

                         ┌──────────────────────────────────────────────────────────────┐
                         │                       DOCKER HOST                            │
                         │                                                              │
  ┌──────────────┐      │  ┌──────────────────────────────────────────────────────────┐ │
  │  Microsoft    │◄────►│  │  email-bot  (Python 3.13)                                │ │
  │  Graph API    │ OAuth │  │                                                          │ │
  │  (Outlook /   │ MSAL  │  │  main.py ─► EmailBot.process_email()                    │ │
  │   Exchange)   │      │  │    ├─ guardrails.py        (input/output validation)     │ │
  └──────────────┘      │  │    ├─ knowledge_base.py     (semantic + keyword search)   │ │
                         │  │    ├─ llm.py               (Anthropic Claude API)        │ │
  ┌──────────────┐      │  │    ├─ trusted_commands.py   (admin command system)        │ │
  │  Anthropic    │◄────►│  │    ├─ escalation.py        (routing engine)              │ │
  │  Claude API   │ HTTPS │  │    ├─ attachments.py      (PDF/image processing)        │ │
  └──────────────┘      │  │    ├─ signature.py          (branded HTML email)          │ │
                         │  │    └─ audit_log.py          (SQLite WAL)                 │ │
                         │  │                                                          │ │
                         │  │  Volumes:                                                │ │
                         │  │    /app/customer/  ◄── config, core docs, KB, branding   │ │
                         │  │    /app/runtime/   ◄── audit DB, logs, tokens, vectors   │ │
                         │  └──────────────────────────┬───────────────────────────────┘ │
                         │                             │ audit.db (WAL, read-only)       │
                         │  ┌──────────────────────────▼───────────────────────────────┐ │
  ┌──────────────┐      │  │  email-bot-monitor  (FastAPI sidecar)                     │ │
  │  Browser      │◄────►│  │  Dashboard: health, KPIs, charts, activity log           │ │
  │  (Dashboard)  │ HTTP  │  │  HTMX auto-refresh every 60s                            │ │
  └──────────────┘      │  └──────────────────────────────────────────────────────────┘ │
                         └──────────────────────────────────────────────────────────────┘

2.1 Core Components

ComponentModulePurpose
Email Clientemail_client.pyMicrosoft Graph API integration — poll, send, reply, mark processed, folder management
OAuth Handlergraph_auth.pyMSAL device-code flow with persistent token caching
LLM Clientllm.pyAnthropic API wrapper — system prompt assembly, core docs injection, confidence/escalation parsing
Knowledge Baseknowledge_base.pyPluggable backends (LanceDB semantic, BM25 keyword), document chunking, PDF extraction
Guardrailsguardrails.pyInput sanitisation (28 injection patterns), output validation (blocklist + credential leak detection)
Admin Commandstrusted_commands.pyEmail-based admin system with sender modes and 2-phase approval workflow
Escalation Engineoutputs/escalation.pyConfigurable routing based on confidence, keywords, LLM flags, and attachment analysis
Attachment Processorprocessors/attachments.pyPDF, text, CSV, image processing; optional domain-specific report parsing
Signature Handlersignature.pyHTML email composition with CID-attached branded logo
Audit Logaudit_log.pySQLite audit trail — every email, guardrail result, LLM usage, escalation, cost
Report Generatorreport_generator.pyMonthly AI-generated self-improvement report with trend analysis
Monitor Dashboardmonitor/app.pyFastAPI sidecar — health, KPIs, charts, activity log via HTMX
Path Resolverpaths.pyCentralised path constants from CUSTOMER_DATA_DIR / RUNTIME_DATA_DIR env vars
Config Loaderconfig_loader.pyYAML config with validation, required section checks, and sensible defaults

2.2 Multi-Customer Design

The platform separates concerns into three tiers, each with independent lifecycle and sync behaviour:

TierEnv VarContainer PathContentsSync
Code(baked into image)/app/Python source, templates, processors--delete rsync (clean replacement)
Customer DataCUSTOMER_DATA_DIR/app/customer/Config, core docs, KB docs, brandingAdditive rsync (no --delete)
Runtime DataRUNTIME_DATA_DIR/app/runtime/Audit DB, logs, tokens, vectors, pending commandsNever synced; persists across deploys

Why this matters: Code updates can be deployed with --delete without risk to customer data. Customer edits made at runtime (via email commands) are preserved. Runtime artefacts like OAuth tokens and audit history are never overwritten.

Each customer lives in its own directory within the source repository:

Source RepositoryTree
email-bot-docker/
├── *.py, processors/, outputs/        # Shared application code
├── templates/                          # System prompt, report template
├── monitor/                            # Dashboard sidecar
├── Dockerfile, Dockerfile.monitor
├── customers/
│   ├── acme-clinic/                    # Customer A
│   │   ├── config.yaml
│   │   ├── docker-compose.yml
│   │   ├── core/                       # Identity, rules, tone, templates
│   │   ├── kb/documents/               # Domain knowledge articles
│   │   └── branding/                   # Signature HTML + logo
│   └── smith-legal/                    # Customer B
│       ├── config.yaml
│       ├── docker-compose.yml
│       ├── core/
│       ├── kb/documents/
│       └── branding/
└── pull-customer.sh                    # Capture runtime edits

2.3 Container Layout

Docker ContainerTree
/app/
├── *.py, processors/, outputs/        # Baked into image via COPY
├── templates/
├── customer/                           # CUSTOMER_DATA_DIR (bind-mounted)
│   ├── config.yaml            (read-only)
│   ├── core/                  (read-write — admin commands can modify)
│   ├── kb/documents/          (read-write — admin commands can modify)
│   └── branding/              (read-write — admin commands can modify)
└── runtime/                            # RUNTIME_DATA_DIR (bind-mounted)
    ├── audit.db, bot.log, token_cache.json
    ├── kb/                    (vector embeddings)
    ├── pending_commands/      (2-phase approval state)
    ├── attachments/           (temp processing)
    └── reports/               (monthly report outputs)

2.4 Path Resolution

All modules import from paths.py — no module constructs its own file paths. The two environment variables control everything:

paths.py (excerpt)Python
CUSTOMER_DATA_DIR = Path(os.environ.get("CUSTOMER_DATA_DIR", "/app/customer"))
RUNTIME_DATA_DIR  = Path(os.environ.get("RUNTIME_DATA_DIR",  "/app/runtime"))

# Customer data
CONFIG_FILE     = CUSTOMER_DATA_DIR / "config.yaml"
CORE_DOCS_DIR   = CUSTOMER_DATA_DIR / "core"
KB_DOCS_DIR     = CUSTOMER_DATA_DIR / "kb" / "documents"
BRANDING_DIR    = CUSTOMER_DATA_DIR / "branding"

# Runtime data
AUDIT_DB        = RUNTIME_DATA_DIR / "audit.db"
TOKEN_CACHE     = RUNTIME_DATA_DIR / "token_cache.json"
KB_PERSIST_DIR  = RUNTIME_DATA_DIR / "kb"

3. Processing Pipeline

Every incoming email passes through a 9-step pipeline. Each step is independently configurable and can be enabled/disabled:

Incoming Email
      │
      ▼
[Step 0] Trusted sender? ──yes──► [Admin Command Handler] ──executed──► Done
      │                                                    ──normal───► continue
      ▼
[Step 1] Rate limit OK? ──no──► Block + Done
      │
      ▼
[Step 2] Input guardrails pass? ──BLOCKED──► Block + Done
      │                          ──SUSPICIOUS──► Flag + continue
      ▼
[Step 3] Knowledge base search ──► relevant context chunks
      │
      ▼
[Step 4] Process attachments ──► extracted text + flags
      │
      ▼
[Step 5] LLM generates reply (system prompt + core docs + KB context + email)
      │
      ▼
[Step 6] Output validation pass? ──no──► Escalate + Done
      │
      ▼
[Step 7] Draft mode? ──yes──► Send draft to reviewer
      │               ──no───► Reply directly to sender
      ▼
[Step 8] Escalation triggers? ──yes──► Send alert to escalation recipients
      │
      ▼
[Step 9] Log timing, tokens, cost ──► Mark email as processed
      │
      ▼
    Done
StepNameConfigurable ViaCan Disable?
0Trusted Commandstrusted_senders listYes (empty list = skip)
1Rate LimitingHardcoded: 20/hr, 100/day per senderNo (always active)
2Input Guardrails28 built-in patternsNo (always active)
3KB Searchknowledge_base.backend, top_k, chunk_sizeYes (empty KB = skip)
4Attachmentsattachments.enabledYes
5LLM Replyllm.model, temperature, max_tokensNo (core function)
6Output ValidationBuilt-in blocklistNo (always active)
7Send / Draftdraft_mode.enabledDraft mode is optional
8Escalationescalation.enabled, triggers, recipientsYes
9Audit & CostAutomaticNo (always active)

The entire pipeline can also be globally paused via processing.enabled: false — the bot continues running (maintaining OAuth tokens and monitoring) but does not process new emails.

4. Knowledge Base

4.1 Search Backends

BackendBest ForHow It WorksDependencies
LanceDB Production — any KB size, best accuracy Encodes documents into 384-dimensional vectors via all-MiniLM-L6-v2; cosine similarity search at query time; disk-persisted in RUNTIME_DATA_DIR/kb/ lancedb, sentence-transformers, torch
BM25 Small KBs (<50 docs), lightweight, no ML deps Tokenised keyword matching with BM25Okapi scoring; in-memory index rebuilt on startup; no persistence needed rank-bm25
Example: LanceDB configYAML
knowledge_base:
  backend: "lance"              # or "bm25"
  embedding_model: "all-MiniLM-L6-v2"
  top_k: 16                     # Number of chunks returned per query
  chunk_size: 2000               # Characters per chunk
  chunk_overlap: 200            # Overlap between chunks

4.2 Document Types

The KB supports .txt, .md, .csv, .json, .html, and .pdf files. Documents are organised into two categories:

CategoryLocationBehaviourExample Use
Core Docs core/ Always included in full in the system prompt. Loaded alphabetically. Defines the bot’s identity, rules, and response guidelines. 00-admins.md (who can manage the bot), 01-master.md (identity + behaviour rules), 02-escalations.md (escalation policy), 03-compliance.md (regulatory constraints), 04-tone-style.md (voice guidelines), 05-email-templates.md (response templates)
KB Docs kb/documents/ Chunked, embedded, and searched per query. Only relevant chunks are injected into context. Pricing sheets, process guides, FAQ articles, reference data, educational content

4.3 Chunking Strategy

  • Text is split into overlapping chunks at configurable size (default: 2000 chars, 200 overlap)
  • Boundary detection prefers sentence endings (. , .\n, \n\n) over arbitrary splits
  • Stable document IDs (MD5 of filepath + chunk index) ensure consistent deduplication
  • Documents are re-ingested on every bot startup to pick up any runtime changes

5. LLM Integration

5.1 Supported Models

ModelIDInput CostOutput CostRecommended Use
Opus 4.6claude-opus-4-6$15.00 / 1M$75.00 / 1MProduction replies — highest quality
Sonnet 4.6claude-sonnet-4-6$3.00 / 1M$15.00 / 1MCost-effective production alternative
Haiku 4.5claude-haiku-4-5-20251001$0.80 / 1M$4.00 / 1MGuardrail pre-screening, report analysis

5.2 Prompt Architecture

The system prompt is assembled from three layers:

  1. Template (templates/system_prompt.txt) — Shared code template with {{CORE_DOCS}} and {{KB_CONTEXT}} placeholders
  2. Core Documents — All files from core/ injected in full (alphabetical order) at {{CORE_DOCS}}
  3. KB Context — Top-k search results injected at {{KB_CONTEXT}} as XML-tagged chunks with source attribution

User messages are wrapped in strict XML delimiters (<incoming_email>) to enforce the boundary between instructions and data.

5.3 Response Parsing

The LLM client extracts structured metadata from responses:

  • <confidence>0.85</confidence> — Self-assessed confidence score (0-1)
  • <escalate type="domain_expert|admin">reason</escalate> — Escalation signal with type and reason
  • Uncertainty language detection (“I’m not confident”, “please consult a professional”, etc.)

All meta-tags are stripped from the final reply before sending.

6. Admin Command System

6.1 Sender Modes

Each trusted sender is assigned a mode that determines how their emails are processed:

ModeBehaviour
commandAll emails treated as admin commands. Instructional updates (e.g., “update our pricing page”) go through the 2-phase smart analysis with before/after preview and approval.
autoLLM intent parsing decides if the email is a command or a normal enquiry. Commands are handled; normal emails fall through to the standard pipeline.
conversationalAlways passes through to the normal pipeline. Useful for senders who are both admins and frequent enquirers.

6.2 Available Commands

CommandPermissionDescription
Update documentupdate_kbCreate or overwrite a knowledge base document
Delete documentdelete_kbRemove a knowledge base document
List documentslist_kbList all KB documents with sizes and modification dates
Show system promptshow_promptDisplay the current system prompt template
Update system promptupdate_promptReplace the system prompt (must retain required placeholders)
Set signatureupdate_signatureUpdate the email signature from an attached image

6.3 Two-Phase Smart Command Flow

Phase 1 — Proposal: When a command-mode sender sends an instructional email, the system loads all current documents, sends the instruction to Claude for analysis, and the LLM proposes specific changes with target file, reasoning, and complete content. The proposal is saved as pending JSON and a before/after preview is emailed to the sender.

Phase 2 — Approval: The sender replies to approve, reject, or request modifications. On approval, the file is written (previous version auto-backed up), and the KB or core docs are reloaded. On rejection, the pending change is discarded.

Security: File operations are sandboxed to core/ and kb/documents/ only. Path traversal is blocked. Extensions are restricted to .md and .txt. Previous versions are automatically backed up with timestamps.

7. Security & Guardrails

7.1 Input Sanitisation

Every incoming email is evaluated against 28 regex patterns in three categories:

  • Injection attempts: “ignore previous instructions”, “you are now a...”, “new instructions:”
  • Prompt extraction: “repeat your prompt”, “show me your instructions”
  • Delimiter manipulation: </system>, [INST], <|im_start|>
Threat LevelConditionAction
SAFENo patterns matchedProcess normally
SUSPICIOUS1-2 indicators matchedProcess with logging — flagged for review
BLOCKED3+ indicators matchedEmail rejected; recorded in audit log

Additional structural checks: special character ratio >40% and single lines >5000 characters both trigger SUSPICIOUS.

7.2 Output Validation

Before any reply is sent, it is checked against:

  • Blocklist phrases: References to system prompts, instructions, internal configuration
  • Credential patterns: API keys, client secrets, tenant IDs
  • Base64 detection: Strings >40 characters that could be leaked credentials

If validation fails, the reply is suppressed and an escalation is triggered instead.

7.3 Rate Limiting

Per-sender sliding window: 20 emails/hour, 100 emails/day. In-memory (resets on bot restart).

7.4 System Prompt Defence

The core documents instruct the LLM to treat all email content as DATA (never instructions), never reveal system configuration, and never follow instructions from within <incoming_email> tags. This provides a defence-in-depth layer beyond the regex-based guardrails.

8. Escalation Engine

8.1 Escalation Types

Two escalation types support different routing needs:

TypeLabelIntended For
Domain Expert[ESCALATION - DOCTOR]Matters requiring professional/domain expertise — e.g., clinical questions, technical assessments, legal opinions
Admin[ESCALATION - ADMIN]Risk, compliance, or operational matters — e.g., complaints, threats, identity concerns, refund requests

8.2 Trigger Sources

  1. LLM self-escalation: The model includes <escalate type="...">reason</escalate> in its response
  2. Confidence threshold: Score below configurable threshold (e.g., 0.7)
  3. Keyword triggers: Configurable list of keywords in subject or body (e.g., “urgent”, “complaint”, “abnormal”)
  4. Attachment flags: Domain-specific flags from the attachment processor (e.g., abnormal lab values)
  5. Uncertainty language: Phrases like “I cannot determine”, “please consult a professional”

8.3 Configuration

Example escalation configYAML
escalation:
  enabled: true
  channels:
    email:
      enabled: true
      recipients:
        - "[email protected]"
        - "[email protected]"
  triggers:
    confidence_threshold: 0.7
    keywords:
      - "urgent"
      - "complaint"
      - "abnormal"
      - "refund"
  bypass_trusted_senders: true

Trusted senders are exempt from escalation when bypass_trusted_senders is enabled.

9. Attachment Processing

When enabled, attachments are processed by content type and their extracted text is included in the LLM prompt context:

TypeMethodNotes
PDFPyMuPDF (fitz)Full text extraction; OCR not included
Text / CSVDirect decodeUTF-8 with fallback
ImagesClaude Vision (primary), Tesseract OCR (fallback)Configurable; Vision supports complex layouts

Limits: Each attachment is capped at 10,000 characters in the prompt. Maximum file size: 25 MB.

Domain-specific parsing: An optional report parser can be configured to detect abnormal values in structured documents (e.g., lab reports, financial statements). Flagged values are passed to the escalation engine.

Example configYAML
attachments:
  enabled: true
  max_size_mb: 25
  supported_types:
    - "application/pdf"
    - "text/plain"
    - "text/csv"
    - "image/png"
    - "image/jpeg"
  report_parsing:
    enabled: true

10. Draft / Review Mode

Draft mode is a production safety mechanism for new deployments or regulated industries. When enabled, the bot composes replies through the full pipeline but sends them to a designated reviewer instead of directly to the original sender.

Each draft email includes:

  • [DRAFT] Re: {original subject} as the subject line
  • Original sender, subject, and received timestamp
  • Confidence score and escalation status
  • The proposed HTML reply with full signature
  • The original email body (first 3000 characters) for context

The reviewer can then forward approved replies, make edits, or handle the enquiry manually.

Enable draft modeYAML
draft_mode:
  enabled: true
  review_recipient: "[email protected]"

Recommended for onboarding: Start every new customer in draft mode. Once the reviewer is satisfied with reply quality and the knowledge base is tuned, transition to live mode by setting enabled: false.

11. Monitoring Dashboard

A FastAPI sidecar container reads the bot’s audit database in read-only WAL mode and serves a real-time dashboard.

11.1 Dashboard Features

  • Health indicator — Green (healthy), amber (warning), red (stale), grey (no data)
  • KPI cards — Total emails, success rate, API cost, avg response time, escalation rate, error rate
  • Charts — Email volume & outcomes (stacked bar), escalation reasons (doughnut), API cost vs volume (dual-axis), confidence distribution (histogram)
  • Activity log — Filterable table of recent emails with sender, subject, status, confidence, cost, and duration
  • Period selector — 24h / 7d / 30d views
  • Auto-refresh — HTMX partial updates every 60 seconds

11.2 Health Logic

StatusCondition
HealthyLast email processed < 24h ago, no errors in last hour
WarningLast email 24-48h ago, OR errors in last hour
StaleLast email > 48h ago

11.3 API Endpoints

EndpointDescription
/api/healthBot health status, last email timestamp, error counts
/api/statsAggregated metrics for selected period
/api/stats/timeseriesTime-bucketed stats for charts (hourly/daily)
/api/emailsPaginated email log with status/tab filtering
/api/costsCost breakdown by model
/api/confidenceConfidence score distribution
/api/escalationsEscalation type breakdown
/api/configCurrent config (API keys and secrets auto-redacted)

12. Monthly Self-Improvement Reports

An AI-generated monthly report analyses the bot’s performance and identifies areas for improvement:

  • Queries audit DB for all emails in the analysis window (default: 30 days)
  • Identifies low-confidence emails, clusters them by topic/domain
  • Runs a secondary LLM analysis (configurable model) to determine root causes and suggest KB improvements
  • Renders an HTML report via Jinja2 template
  • Emails report to configured recipients
Example configYAML
monthly_report:
  recipients:
    - "[email protected]"
  confidence_threshold: 0.7     # Analyse emails below this score
  analysis_model: "claude-haiku-4-5-20251001"

Reports can be triggered manually (python main.py --report), as a dry run (--report --dry-run), or automated via cron.

13. Deployment & Operations

13.1 Two-Phase Deploy

The deploy script executes four steps:

  1. Phase 1 — Sync Code (rsync --delete) — Clean replacement of all Python source. Excludes customers/, runtime/, customer data dirs.
  2. Phase 2 — Sync Customer Data (additive rsync) — config.yaml, docker-compose.yml, core/, kb/, branding/. No --delete to protect runtime edits.
  3. Phase 3 — Ensure Runtime Dirs — Creates runtime/{kb,pending_commands,attachments,reports} if missing.
  4. Phase 4 — Build & Restartdocker compose up -d --build

13.2 Pull Customer Workflow

After a customer has modified documents via email commands:

Capture runtime edits back to sourceBash
./pull-customer.sh <customer-name> <target-name>
git diff customers/<customer-name>/
git add customers/<customer-name>/ && git commit -m "Sync customer data from live"

13.3 Docker Compose Template

customers/<name>/docker-compose.ymlYAML
services:
  email-bot:
    build: .
    container_name: email-bot-<name>
    restart: unless-stopped
    environment:
      - CUSTOMER_DATA_DIR=/app/customer
      - RUNTIME_DATA_DIR=/app/runtime
    volumes:
      - ./config.yaml:/app/customer/config.yaml:ro
      - ./core:/app/customer/core
      - ./kb:/app/customer/kb
      - ./branding:/app/customer/branding
      - ./runtime:/app/runtime

  email-bot-monitor:
    build:
      context: .
      dockerfile: Dockerfile.monitor
    container_name: email-bot-monitor-<name>
    restart: unless-stopped
    ports:
      - "<host-port>:8081"
    environment:
      - AUDIT_DB_PATH=/app/runtime/audit.db
      - CONFIG_PATH=/app/customer/config.yaml
    volumes:
      - ./runtime:/app/runtime:ro
      - ./config.yaml:/app/customer/config.yaml:ro

13.4 Rollback

Git tags are created for each release. To rollback:

Bash
git checkout <tag>
./deploy.sh email-bot <customer>

13.5 CLI Commands

CommandDescription
python main.pyStart the bot (normal operation)
python main.py --authInteractive Microsoft OAuth sign-in (one-time setup)
python main.py --ingestRe-ingest KB documents and exit
python main.py --statsPrint processing stats for last 7 days
python main.py --reportGenerate and send monthly report
python main.py --report --dry-runGenerate report without sending (prints HTML)
python main.py --config /path/to/config.yamlUse a custom config file

14. Configuration Reference

SectionRequiredPurpose
emailRequiredMicrosoft Graph credentials (client_id, tenant_id), mailbox address, poll interval, optional sender domain filtering
llmRequiredAnthropic API key, model ID, temperature, max tokens
draft_modeOptionalEnable/disable draft review mode; review_recipient email address
processingOptionalGlobal on/off switch (enabled: true/false)
knowledge_baseOptionalBackend (lance/bm25), embedding model, chunk size, top-k
attachmentsOptionalEnable/disable, supported MIME types, max size, report parsing
escalationOptionalEnable/disable, email recipients, keyword triggers, confidence threshold, trusted sender bypass
trusted_sendersOptionalList of trusted senders with email, mode (auto/command/conversational), and per-command permissions
loggingOptionalLog level, full context logging toggle (defaults applied)
monthly_reportOptionalRecipients, analysis model, confidence threshold

Minimal Configuration

Minimum viable config.yamlYAML
email:
  client_id: "your-azure-app-client-id"
  tenant_id: "your-azure-tenant-id"
  mailbox: "[email protected]"
  poll_interval: 60

llm:
  api_key: "sk-ant-..."
  model: "claude-sonnet-4-6"

Full-Featured Configuration

Production config.yaml exampleYAML
email:
  client_id: "azure-app-client-id"
  tenant_id: "azure-tenant-id"
  mailbox: "[email protected]"
  poll_interval: 300                  # 5 minutes
  allowed_sender_domains:             # Only process from these domains
    - "gmail.com"
    - "outlook.com"
    - "example.com"

llm:
  api_key: "sk-ant-..."
  model: "claude-opus-4-6"
  temperature: 0.3
  max_tokens: 4096

draft_mode:
  enabled: true
  review_recipient: "[email protected]"

knowledge_base:
  backend: "lance"
  embedding_model: "all-MiniLM-L6-v2"
  top_k: 16
  chunk_size: 2000

attachments:
  enabled: true

escalation:
  enabled: true
  channels:
    email:
      enabled: true
      recipients:
        - "[email protected]"
        - "[email protected]"
  triggers:
    confidence_threshold: 0.7
    keywords: ["urgent", "complaint", "refund"]

trusted_senders:
  - email: "[email protected]"
    mode: "command"
    permissions: ["update_kb", "delete_kb", "list_kb", "show_prompt"]
  - email: "[email protected]"
    mode: "conversational"

monthly_report:
  recipients: ["[email protected]"]

logging:
  level: "INFO"

15. Customer Onboarding Checklist

To deploy the platform for a new customer:

  1. Create customer directory: customers/<name>/ with config.yaml, docker-compose.yml, core/, kb/documents/, branding/
  2. Write core documents (00-05.md) defining the bot’s identity, rules, escalation policy, compliance constraints, tone/style, and email templates
  3. Populate knowledge base with domain-specific documents (pricing, FAQs, processes, articles)
  4. Configure branding: signature.html with disclaimer and contact info; email-logo.png for inline CID attachment
  5. Set up Azure AD app with Mail.ReadWrite and Mail.Send permissions for the shared mailbox
  6. Configure config.yaml with API keys, mailbox, model selection, escalation recipients, trusted senders
  7. Enable draft mode for initial deployment
  8. Deploy: ./deploy.sh email-bot <name>
  9. Run OAuth: docker compose exec email-bot python main.py --auth
  10. Verify: Check monitor dashboard, send test email, confirm draft arrives at reviewer
  11. Tune: Review drafts, adjust KB and core docs, refine escalation triggers
  12. Go live: Set draft_mode.enabled: false when satisfied with reply quality