-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
SuperElectron edited this page Aug 21, 2026
·
3 revisions
Single Rust binary, three run modes: serve (HTTP), worker (jobs), cli (operator commands).
| Layer | Tech | Why |
|---|---|---|
| HTTP: webhooks, health, control API | axum | harness (Claude Code / OpenClaw) drives system through control API |
| Jobs: queues, cron, retries, concurrency | apalis on Postgres | replaces Trigger.dev; no extra infra beyond Postgres. Queue lives in apalis/apalis_meta schemas (search_path pinned) so its migrations never touch public._sqlx_migrations. Side effect: apalis installs pgcrypto with its functions in apalis_meta — pgcrypto is database-global, so an app migration adding CREATE EXTENSION IF NOT EXISTS pgcrypto is a no-op and its functions are not on public's path |
| Operational store + audit | Postgres (sqlx, migrations in repo) | contacts, companies, outreach_log, web_research, audit_history, capacity |
| Semantic memory | Mem0 self-hosted (Apache-2.0, REST) | replaces Personize: extraction (add), recall (search), digest. Its LLM = local gpt-oss |
| LLM | OpenAI-compatible client → gpt-oss-120B on DGX | provider swappable via env |
| Structured output | serde + schemars | typed LLM responses, parse + repair |
| Governance | own module | policy docs (ICP, brand voice, playbook, signal defs) + trigger keywords → injected into prompts |
docker compose up: app + postgres(+pgvector) + mem0. Runs anywhere. Zero external platforms.
| Area | In | Cut |
|---|---|---|
| CRM | HubSpot, CSV import | Salesforce, Clay |
| Email send | Gmail (multi-sender rotation), SendGrid | Smartlead, raw SMTP |
| Reply monitoring | Gmail API polling | IMAP |
| Social | LinkedIn via HeyReach (webhook events in) | — |
| Voice | — | whole channel (Vapi/Bland/ElevenLabs) |
| Prospect data | Apollo (discover/enrich), Tavily (web research) | — |
| Notifications | Slack (alerts, digests, error handler) | — |
src/domain/ types: contact, company, engagement, signal, task
src/config/ env, targeting (ICP), cadence, messaging, agent modes
src/db/ repositories + audit + capacity + workspace state
src/llm/ client, schemas, output, governance, multi-step composition
src/memory/ mem0: add / search / token-budgeted digest
src/clients/ apollo, tavily
src/connectors/ trait + gmail, sendgrid, slack, hubspot, heyreach
src/workflows/ sync, discovery, research, accounts, outreach, analysis, reporting, tasks
src/jobs/ apalis registrations + cron schedules
src/http/ webhooks router (handler registry), control API
src/cli/ serve, worker, job run, status, tail, gmail-auth, sync-csv
- Sync (HubSpot pull / CSV) → Postgres + Mem0 ingest
- Discovery/enrichment (Apollo) → new contacts/companies
- Research (Tavily) + signal detection → scores, memories
- Account strategy → preflight → generation (recall + governance + LLM) → send (Gmail/SendGrid/HeyReach) with capacity limits, send windows, opt-out
- Inbound: Gmail reply polling + HeyReach webhooks → classify → act (notify Slack, log HubSpot, stop sequence)
- Reporting: daily digest, weekly report → Slack
-
cp .env.example .env— fill keys (Apollo, Tavily, HubSpot, Gmail OAuth, SendGrid, HeyReach, Slack webhook, LLM endpoint) docker compose up -d postgres mem0-
cargo run -- cli gmail-auth(once) -
cargo run -- serve+cargo run -- worker
- Secrets in .env, never committed. Post-v1 option: jentic-one credential broker in front of connectors (transport-pluggable trait designed for it).
- Audit table records property changes with confidence + updatedBy.
See Home, Development-Plan.
Copy migration 0011 (email normalization), not 0005. 0011 merges: children re-point to the winner before any delete, terminal status (opted_out, disqualified) propagates onto the survivor, multiple sequence states collapse to the furthest-along, and losers go to a backup table. 0005 deletes with cascades — it shipped before the pattern existed and only ever ran on empty or junk data. In 0011, DROP INDEX and CREATE UNIQUE INDEX IF NOT EXISTS must stay adjacent: the IF NOT EXISTS is only safe because the DROP guarantees absence.