System Architecture Overview
Always-on prospecting to proposal engine — research targets, generate letters, mail via API, dial via Salesfinity, share a single URL that closes deals.
317 Pages Live
10 AI Agents
7 LLM Models
250/150 Governor
Business Flow
Every prospect moves through five stages. Each stage is automated. The 250/150 governor prevents the next batch until the current batch is fully worked.
🔍
RESEARCH
Find targets, qualify, score. 10-query acquisition check. Story intelligence layer.
Supabase targets table
📄
GENERATE
Build hub page, letter, proposal, company story page from Supabase data.
Vercel · 317 pages
✉️
MAIL
Print and mail physical letters via Lob API. Max 250 per batch.
Lob API · letter_campaigns
📞
CALL
Parallel dial via Salesfinity. Track until 150 contacts hit 5 calls each.
Salesfinity · call_outcomes
🎯
CLOSE
Share single personalized URL on phone call. Prospect sees their story.
One URL per prospect
250/150 Governor: Send a max of 250 letters per batch. HARD STOP. Monitor until 150 of those contacts have been called 5 times each. Only then unlock the next batch. Enforced at three layers: Python logic, database CHECK constraints, and a UNIQUE INDEX that prevents two active batches simultaneously.
Architecture Map
Three layers: Claude Code (where humans build), OpenClaw (where agents run), Supabase + Vercel (where data lives and pages deploy).
Mac Mini (Always On)
Development
Claude Code
Opus Architect (strategy)
Sonnet Builder (features)
Haiku Executor (bulk ops)
MCP: Exa, Fireflies, Gmail, Slack, Calendar, Drive, Chrome
Orchestration
OpenClaw Gateway :18789
10 Specialized Agents
8 Cron Jobs (paused)
Telegram Bot
Models: DeepSeek, Gemini, GPT-4o Mini, Ollama
Local Services
ML + Networking
Ollama :11434 (embeddings)
ChromaDB (vector store)
Tailscale (100.112.160.48)
↓ ↓ ↓
Cloud Services
Database
Supabase (PostgreSQL)
targets (201+ rows)
companies, contacts
pipeline_log, call_log
meeting_notes
campaign_batches, letter_campaigns
Hosting
Vercel
317 static HTML pages
/api/letters/ (serverless)
/api/webhooks/lob.js
Auto-deploys on git push
External APIs
Integrations
Lob (physical mail)
Salesfinity (dialer)
Telegram (notifications)
Exa (semantic search)
Engines
Letter Engine lib/letter_engine.py
Renders physical letters for Lob mail API from Supabase company data and vertical-specific EBITDA benchmarks. Supports three touch variants per prospect. Jinja2 templating with 24 variables. Print-ready HTML at 8.5×11, Georgia serif, no color.
| Input | Company ID + variant (touch_1, touch_2, touch_3) |
| Output | Lob-ready HTML string |
| Data Sources | Supabase companies & contacts tables + 7 vertical EBITDA benchmarks (water treatment, HVAC, plumbing, roofing, pest control, concrete, flooring) |
| Key Functions | render() render_all_variants() _build_ebitda_narrative() |
Tone rule: Operator narrative, not PE finance speak. "I know what it's like to build something with your hands and wonder what happens to the team when you're ready to step back."
Meeting Engine v2 lib/meeting_engine_v2.py
Interactive meeting prep pages with three meeting types: Discovery, Financial Review, Engagement. Auto-saves to Supabase with 600ms debounce. Completeness tracking unlocks downstream documents as fields are filled.
| Tabs | Pre-Meeting · During-Meeting · Post-Meeting |
| During-Meeting | Owner profiles, emotional temperature slider, revenue mix, margin grid (gross/EBITDA/SDE), key employees table, deal breakers, verbatim quotes |
| Unlock Tracker | Letter at 3 fields → Buyer targeting at 5 → Proposal at 6 → Full pipeline at 10 |
Campaign Manager lib/campaign_manager.py
Governs the 250/150 letter-to-call pipeline. Three enforcement layers prevent batch overflow.
| Layer 1 | Python logic — send_batch() checks count, check_threshold() gates next batch |
| Layer 2 | DB constraint — CHECK (letter_count <= 250) on campaign_batches |
| Layer 3 | Unique index — Only one active batch per entity at any time |
| Notification | Telegram alert on batch milestone (complete, threshold met, hard stop) |
Page Regeneration scripts/regenerate.py
Incremental and full-rebuild modes for hub pages. Git push after generation triggers Vercel auto-deploy.
Incremental
Only rebuilds pages for companies with new/stale research (RESEARCHED status + no report_generated_at).
Full Rebuild
All 171+ non-disqualified targets. Run when templates change. Supports --entity filter.
Lob Mail Client lib/lob_client.py
HTTP wrapper for Lob physical mail API. Sends print-ready letters, tracks delivery status via webhooks.
| Send | send_letter(html, to_address, from_address) → letter_id, tracking_url, expected_delivery_date |
| Track | get_letter_status(letter_id) + webhook at /api/webhooks/lob.js |
| Status | API Verified (Live Key) |
Salesfinity Dialer lib/salesfinity_client.py
AI parallel dialer integration. Pushes contacts for calling, fetches outcomes, syncs back to Supabase.
| Push | create_dialer_list(contacts) → list_id |
| Fetch | get_call_outcomes(list_id) → connected, voicemail, no answer, interested, etc. |
| Sync | sync_outcomes_to_supabase() writes call_log records with outcome, duration, timestamp |
Claude Code Sub-Agents
Three specialized agents auto-route by task complexity. Defined in ~/.claude/agents/.
Haiku Executor
Fast, no-frills execution. No reasoning.
Model: Claude Haiku 4.5
Cost: ~$0.05/task
Tools: Bash, Read, Glob
Git ops, file moves, health checks, ls, status commands
Sonnet Builder
Balanced execution + moderate reasoning.
Model: Claude Sonnet 4.6
Cost: ~$0.50/task
Tools: Bash, Read, Write, Edit, Glob, Grep
Config edits, JSON, hooks, integrations, bug fixes
Opus Architect
Strategic design. High reasoning.
Model: Claude Opus 4.6
Cost: ~$2.00/task
Tools: All tools
Architecture, trade-offs, system design, debugging
OpenClaw Agent Fleet
10 specialized agents running on cheap LLMs for high-volume autonomous work. Multi-model strategy: expensive models build, cheap models research.
| Agent | Model | Role | Cost Tier |
| main | DeepSeek Chat | Primary orchestration and routing | $0.27/M in |
| researcher | Gemini 2.5 Flash Lite | Web research, target qualification | Free/minimal |
| executor | GPT-4o Mini | Task execution, command running | $0.15/M in |
| validator | DeepSeek V3 | Research quality checks | $0.27/M in |
| auditor | DeepSeek V3 | Pipeline health, compliance audits | $0.27/M in |
| classifier | DeepSeek V3 | Company and data classification | $0.27/M in |
| controller | DeepSeek Chat | Pipeline flow control and gating | $0.27/M in |
| listener | Gemini 2.5 Flash Lite | Channel monitoring (Telegram, email) | Free/minimal |
| certifier | DeepSeek V3 | Data quality certification | $0.27/M in |
| nurturer | GPT-4o Mini | Outreach relationship management | $0.15/M in |
Scheduled Routines
8 autonomous routines designed for the pipeline. Currently paused pending credential sync and agent instruction files.
| Routine | Frequency | What It Does | Status |
| batch-pull | Every 2h | Pull NEW targets from Supabase, set to RESEARCHING | Paused |
| research-loop | Every 30m | Run 5-step research sequence on RESEARCHING targets | Paused |
| quality-review | Every 30m | Review against $5K consulting report quality bar | Paused |
| morning-brief | Every 4h | Pipeline counts, errors, cost tracking summary | Paused |
| publish-and-send | Every 1h | Generate reports for approved targets, queue outreach | Paused |
| dialer-update | Every 2h | Push REPORT_LIVE contacts to Salesfinity with call scripts | Paused |
| heartbeat | Every 15m | Health check: stuck targets, errors, pipeline counts | Paused |
| weekly-maint | Weekly | Memory flush, error patterns, cost tracking vs $1.50 cap | Paused |
Database Schema
| Table | Purpose | Key Fields | Status |
| targets | Master acquisition target list | company_name, pipeline_status, vertical, acquisition_status | Live (201+ rows) |
| companies | Enriched company profiles | name, city, state, revenue, personalized_url | Live |
| contacts | Owner/decision-maker contacts | first_name, last_name, phone, email, role | Live |
| pipeline_log | Audit trail for all agent actions | agent, action, details, timestamp | Live |
| call_log | Salesfinity call outcomes | contact_id, outcome, duration, called_at | Live |
| deal_research | Deep research notes per deal | target_id, research_data | Live (expanding) |
| meeting_notes | Per-field meeting data capture | meeting_id, field_name, field_value | Migration ready |
| campaign_batches | 250/150 governor state | batch_number, letter_count, calls_completed | Migration ready |
| letter_campaigns | Lob letter tracking | lob_letter_id, variant, status, delivered_at | Migration ready |
| call_outcomes | Per-call attempt tracking (max 5) | target_id, attempt_number, outcome | Migration ready |
Pipeline States
NEW
→
RESEARCHING
→
RESEARCHED
→
NEEDS_REVIEW
→
REPORT_LIVE
Quality gate: Every target must meet the "$5,000 consulting report" standard before advancing past NEEDS_REVIEW. Every status transition is logged to pipeline_log with agent name, action, and reasoning.
Enrichment Sources
| Source | What It Provides | Integration |
| Exa | Semantic web search, company discovery, contact enrichment | MCP (web_search_exa, crawling_exa) |
| Google Search API | Broad web discovery, news, press releases | Gemini provider via OpenClaw |
| Fireflies | Meeting transcripts, summaries, action items | MCP (fireflies_get_transcript) |
| Gmail | Email threads, contact history | MCP (gmail_search_messages) |
| Slack | Team discussions, deal context | MCP (slack_search_public) |
| Google Calendar | Meeting schedules, availability | MCP (gcal_list_events) |
| Google Drive | Shared documents, presentations | MCP (google_drive_search) |
| Ollama | Vector embeddings (nomic-embed-text, 137M params) | Local API :11434 |
| ChromaDB | Semantic search across all ingested data | Local Python API |
Story Intelligence Layer
Beyond financial data, the system hunts for human stories about each founder: YouTube interviews, podcast appearances, local news features, Google reviews mentioning the owner by name, trade publication profiles, BBB complaint responses. These feed the Company Story Template — a storyboard page with photos, pull quotes, generational narrative, and a "What Happens to the Team" section.
Business Rules Engine
Rules are stored at multiple levels to prevent any single point of override.
| Rule Type | Where Stored | Example |
| Pipeline gates | Python code (campaign_manager.py) | 250 letter max, 150/5x call threshold |
| Database constraints | Supabase CHECK + UNIQUE INDEX | Only one active batch per entity |
| Quality standards | SOUL.md (agent instructions) | "$5,000 consulting report" quality bar |
| Scoring rubrics | letter_engine.py vertical benchmarks | EBITDA floors/ceilings/medians per vertical |
| Classification rules | Acquisition status check (SOUL.md) | 10-query detection protocol |
| Tone rules | Letter template + prompt files | Operator narrative, not PE finance speak |
| Cost caps | Campaign manager + cron config | $1.50 per target research cost limit |
| Retry logic | Self-repair protocol | Exponential backoff: 30s / 60s / 120s / SKIP |
Cost Model
| Component | Cost Per Unit | Usage |
| Claude Opus 4.6 (architect) | ~$15/M in, $75/M out | Strategic design only |
| Claude Sonnet 4.6 (builder) | ~$3/M in, $15/M out | Feature building, ~$0.50/session |
| Claude Haiku 4.5 (executor) | ~$0.25/M in, $1.25/M out | Bulk execution |
| DeepSeek Chat (agents) | $0.27/M in, $1.10/M out | Autonomous agent work |
| Gemini Flash Lite (research) | Free tier / minimal | Research agent, listener |
| GPT-4o Mini (execution) | $0.15/M in, $0.60/M out | Executor + nurturer agents |
| Ollama (embeddings) | $0.00 | Local nomic-embed-text |
| Lob (physical mail) | ~$1.50/letter | Per letter mailed |
| Supabase | Free tier | Database + auth |
| Vercel | Free tier | Static hosting + serverless |
Target all-in cost per prospect: Under $5.00 (research + letter + tracking). Research agent uses DeepSeek/Gemini at <$0.30/M tokens. Expensive Claude models reserved for human-facing development only.
Infrastructure
Mac Mini (Always-On Host)
Claude Code development environment
OpenClaw gateway on :18789
Ollama ML server on :11434
ChromaDB vector database
Tailscale mesh: 100.112.160.48
Cloud Stack
Supabase — PostgreSQL + REST API
Vercel — Static hosting + serverless functions
GitHub — Source control, auto-deploy trigger
Lob — Physical letter mailing
Salesfinity — AI parallel dialer
Communication
Telegram @MacMiniEwingBot — primary control channel
Decisions only, no noise, links not paths
Slack — team collaboration (MCP integrated)
Overnight Batch Runner
Bash script runs 9 sequential headless Claude Sonnet sessions
Each session builds a specific feature from prompt files
Runs while operator sleeps — logs to overnight-logs/
Key Design Decisions
| Decision | Rationale |
| Operator narrative over PE finance speak | Letters sound like someone who built a business, not someone who buys them. Trust builds faster. |
| OpenClaw agents over custom Agent SDK | Single orchestration platform. Don't build a framework when one exists. |
| Cheap models for volume, expensive for strategy | DeepSeek/Gemini at <$0.30/M for research. Claude Opus only for architecture decisions. |
| Local embeddings (Ollama) over cloud | Zero marginal cost for vector search across transcripts and emails. |
| Hard governor (250/150) over soft limits | Database constraints enforce discipline. No config toggle can override. |
| Single URL as the closer | Every prospect gets one page that tells their story better than they could. That URL is the product. |
| Hybrid file + database bridge | Speed of local file reads with durability of Supabase persistence. |
| Telegram as primary control channel | Operator controls everything from phone. Decisions only, no noise. |
Current Status
Live Now
Letter engine + templates
Lob API (live key verified)
Tailscale + Ollama + ChromaDB
Next to Activate
Missing database tables (SQL written)
Agent SOUL.md instruction files
Cron scheduler activation
ChromaDB ingestion pipeline
Campaign manager E2E test
Built by Ewing Gillaspy with Claude Code (Anthropic) · OpenClaw v2026.3.28 · March 30, 2026