factory
AI factory engine — hub-and-spoke, asyncio, multi-channel.

factory runs 24/7 on your own hardware, connects Telegram and Discord to specialized AI agents, and routes every conversation through isolated per-scope pools. No cloud lock-in. No subscription. Your data stays on your machines.
Why
Most personal AI assistants are cloud-hosted: your data leaves your machine, your conversations are stored on someone else's servers, and the service disappears the moment a company pivots.
factory exists to run on your own hardware — a Raspberry Pi, a home server, anything always-on — and connect your preferred chat platforms (Telegram, Discord) to AI agents you control. No API keys sold to third parties. No subscription. No lock-in. When you want a different model, you swap it in TOML.
It's for developers who want a persistent personal AI without giving up ownership of their data or infrastructure.
How it works
- Channel adapters (Telegram, Discord) run as separate processes. They normalize incoming messages and publish them over NATS (
factory.inbound.<platform>.<bot_id>).
- The Hub (
factory-hub process) subscribes to NATS, routes each message to the right agent via typed (platform, bot_id, scope_id) bindings — one pool per conversation scope (chat, thread, channel).
- The Agent processes the message, calls the LLM, and publishes the response over NATS (
factory.outbound.<platform>.<bot_id>). The adapter's NatsOutboundListener delivers it to the platform.
Architecture
chat adapters factory-hub workers
(telegram·discord) │ (clipool·omp)
│ │ │
│ inbound.<platform> │ worker.cmd │
├───────────────────────►├───────────────────────►│
│ │ │
│ │ ┌────────────┐ │
│ │ │ CliPool / │ │
│ │ │ OmpWorker │ │
│ │ └────────────┘ │
│ │ │
│ outbound.<platform> │ │
◄────────────────────────┘ NATS bus
│
infra (gh-helper·turn-writer·blobstore)
Production: Nine containers on M₁ communicate via a single NATS server (factory-nats). Hub: factory-hub. Chat adapters: factory-telegram, factory-discord. Workers: factory-clipool, factory-omp. Infra: factory-gh-helper, factory-turn-writer, factory-blobstore. Each runs in its own container.
Development: factory start runs everything in one process with an embedded NATS server.
Features
Channels & Routing
| Feature | Detail |
|---|
| Channels | Telegram (aiogram v3 · polling + webhook) · Discord (discord.py v2 · gateway) |
| Routing | Typed RoutingKey(platform, bot_id, scope_id) — scope = chat / thread / channel |
| Multi-bot | Multiple bots per platform, each with its own agent binding |
| Concurrency | Sequential per scope (asyncio.Task) · parallel across scopes |
| Backpressure | Bounded queue (100) → immediate ack + blocking await |
AI & Memory
| Feature | Detail |
|---|
| LLM | Claude CLI subprocess (primary) · smart routing (complexity-based model selection) |
| Agents | Stateless singleton · isolated per-scope pools · AgentStore (SQLite) |
| Memory | 5 levels: working (L0 compaction) → session → episodic → semantic (FTS5 + embeddings) → procedural |
| Session commands | /vault-add, /explain, /summarize, /search — scrape → LLM → vault |
Voice & Security
| Feature | Detail |
|---|
| Voice | STT via voicecli (faster-whisper) · TTS via voicecli (Qwen) · OGG/Opus · Discord voice |
| Auth | TrustLevel per adapter (owner/trusted/public/blocked) · outbound verification |
| Security | Prompt injection guard · sandboxed skills · hmac webhook verification |
Quick start
# 1. Install
uv sync && source .venv/bin/activate
# 2. Configure
cp config.toml.example config.toml
# Edit config.toml: set bot_id, agent, owner_users
# 3. Store credentials (encrypted)
factory bot secret install telegram <bot_id>