Architecture
System design — harness, memory, channels, and deployment model.
System components
┌─────────────────────────────────────────────────────────────────┐
│ Your SaaS Product │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌─────────────────────┐ │
│ │ Frontend │ │ Backend │ │ Database │ │
│ │ @aelio/chat│ │ @aelio/sdk │ │ Postgres/MySQL/... │ │
│ └──────┬──────┘ └──────┬───────┘ └──────────▲──────────┘ │
│ │ │ │ │
└─────────┼─────────────────┼───────────────────────┼─────────────┘
│ │ │
│ /widget/ws │ /sdk (outbound WS) │ tool handlers
▼ ▼ │ query DB
┌─────────────────────────────────────────────────────────────────┐
│ Aelio Server │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ Channels │ │ Harness │ │ Safety │ │ Memory │ │
│ │ Web · WA │ │ Turn eng │ │ Gates │ │ sqlite-vec │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Identity │ │ LLM │ │ Proactive│ │
│ │ Sessions │ │ Providers│ │ Outreach │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────┐
│ LLM Provider │
│ OpenAI · Claude │
│ Gemini · Groq │
└──────────────────┘The Harness (turn engine)
Default on (harness.enabled: true). Deterministic loop with hard budgets:
Plan — LLM chooses between a shallow direct answer or a deep multi-tool plan.
Bind — semantic tool matching maps intent to registered SDK functions.
Resolve — gathers any missing required arguments from the customer.
Execute — calls SDK tools in parallel where possible, respecting safety gates.
Synthesize — composes the final natural-language reply from tool results.
Hard budgets
The harness enforces max tool calls, replans, wall-clock time, and token limits. Falls back to a legacy single-loop when harness.enabled: false.
Safety model
Every tool has a safety level evaluated before execution:
| Level | Gate behavior |
|---|---|
read | Auto-allowed |
write | Requires user confirmation |
destructive | Blocked in V1 |
Destructive actions are blocked
Actions with safety: 'destructive' are rejected outright in V1 and will never be executed, regardless of user confirmation.
Additional gates: lifecycle state tool filtering, guard conditions, missing required args.
Memory architecture
| Component | Technology |
|---|---|
| Conversation history | SQLite (Drizzle ORM) |
| Vector embeddings | sqlite-vec |
| Fact extraction | LLM (async, post-turn) |
| Fact recall | Top-K vector similarity search |
| Optional storage | Sunjet/Astrolobe (Rust .vss engine) |
Channel adapters
| Channel | Adapter | Config |
|---|---|---|
| Web widget | Built-in /widget/ws | channels.web in config.yaml |
| WhatsApp (Meta) | Built-in /wa/webhook | channels.whatsapp.provider: meta |
| BYO provider | SDK onSend + ingest | channels.whatsapp.provider: sdk |
Deployment model
Single-container Docker deployment (~190MB distroless image):
docker run -p 3010:3010 \
-e AELIO_SDK_SECRET=secret \
-e OPENAI_API_KEY=sk-... \
-v ./config.yaml:/config/config.yaml \
aelio/server:latestTemplates for Railway, Render, and Fly.io included in the repo.
Monorepo structure
Aelio-Convox/
├── sdk/node/ @aelio/sdk (npm)
├── sdk/python/ aelio-sdk (PyPI)
├── chat/ @aelio/chat (npm)
├── server/ @aelio/server (Docker)
├── packages/
│ ├── protocol/ Wire protocol + Zod schemas
│ ├── core/ Turn engine, harness, memory, safety
│ ├── db/ Drizzle SQLite + sqlite-vec
│ ├── llm/ LLM provider abstraction
│ └── channels/ WhatsApp adapter
├── examples/ Working integrations per stack
└── config*.yaml Runtime config profilesTech stack
| Layer | Technology |
|---|---|
| Language | TypeScript (Node ≥ 20), Python ≥ 3.9 |
| Server | Fastify 5 + WebSocket |
| Database | SQLite + Drizzle + sqlite-vec |
| LLM | OpenAI, Anthropic, Gemini, Groq, Ollama, mock |
| Widget | Preact + Vite |
| Protocol | JSON over WebSocket (Zod-validated) |
| Deployment | Docker (distroless) |