A purpose-built Python AI assistant for personal use.
Runs on Mac. Talks via Telegram. Remembers everything.
Built from scratch. ~3,000 lines. Ships today.
_ _ _ _____ ___ ___ ___ _____ ___
/_\ | \| |_ _|_ _| \/ _ \_ _| __|
/ _ \| .` | | | | || |) | (_) || | | _|
/_/ \_\_|\_| |_| |___|___/ \___/ |_| |___|
Less framework. More you.
Antidote is a personal AI assistant that:
- Talks to you on Telegram — no web UI, no dashboard, just message your bot
- Remembers everything — SQLite FTS5 full-text search memory that persists across restarts
- Uses any model — 100+ models via OpenRouter (Claude, GPT, DeepSeek, Llama, etc.)
- Runs on your Mac — always on, auto-restarts on crash via launchd
- Has tools — reads/writes files, runs shell commands, searches memory
- Encrypts your secrets — API keys stored with Fernet encryption tied to your hardware
- Has a personality — configurable soul, behavior rules, and user preferences in markdown
- Not a framework. Not a library. Not a platform.
- No Docker. No Kubernetes. No YAML configs.
- No multi-user auth. No web dashboard. No cloud deployment.
- No vector databases. No embeddings. No RAG pipelines.
- Just an AI assistant that works.
# Clone and enter
git clone <this-repo>
cd antidote
# One command to set up and run
./start.shThe setup wizard walks you through everything:
✓ Python 3.11
─── Step 1: Telegram Bot Token ───
─── Step 2: OpenRouter API Key ───
─── Step 3: Default AI Model ───
─── Step 4: Name Your AI ───
─── Step 5: Personality ───
─── Building ───
✓ Secrets encrypted and stored
✓ Config written
✓ Identity files written
✓ Memory database seeded
╭─ Done ─╮
│ Antidote is ready. │
╰────────╯
After setup, just:
antidoteantidote/
├── antidote/
│ ├── main.py # Entry point — wires everything
│ ├── config.py # Singleton config with dot-access
│ ├── agent/
│ │ ├── loop.py # Core brain — LLM + tool loop (max 5 rounds)
│ │ └── context.py # System prompt builder (identity + memory)
│ ├── providers/
│ │ ├── base.py # Provider ABC + dataclasses
│ │ ├── openrouter.py # 100+ models via LiteLLM
│ │ └── ollama.py # Local LLM fallback (free, private)
│ ├── channels/
│ │ └── telegram.py # Long-polling, typing indicator, markdown
│ ├── memory/
│ │ └── store.py # SQLite FTS5 with bm25 ranking
│ ├── tools/
│ │ ├── registry.py # Tool discovery and registration
│ │ ├── filesystem.py # read_file, write_file, list_directory
│ │ └── shell.py # run_command (with safety blocklist)
│ └── security/
│ ├── secrets.py # Fernet encryption (hardware UUID key)
│ └── safety.py # Command blocklist + audit log
├── workspace/
│ ├── SOUL.md # AI personality
│ ├── AGENTS.md # Behavior rules
│ ├── USER.md # Your preferences
│ └── MEMORY.md # Bootstrap facts
├── wizard.py # Interactive setup wizard
├── start.sh # One-command launcher
└── com.antidote.agent.plist # macOS auto-restart
You (Telegram) → TelegramChannel → AgentLoop → Provider (OpenRouter/Ollama)
↕ ↕
ToolRegistry LLM Response
↕ ↕
MemoryStore Tool Calls?
↕
Execute → Loop back
(max 5 rounds)
- You send a Telegram message
- The context builder assembles: personality + relevant memories + conversation history
- The LLM responds, optionally calling tools (file ops, shell, memory)
- Tool results feed back into the LLM for up to 5 rounds
- Final response goes back to Telegram
- Conversation summary saved to memory
Antidote's personality is defined in markdown files you can edit:
| File | Purpose |
|---|---|
SOUL.md |
Who the AI is — personality, communication style, values |
AGENTS.md |
How it behaves — when to use tools, how to manage memory |
USER.md |
Who you are — preferences, populated over time |
MEMORY.md |
Bootstrap facts — seeded on first run |
SQLite FTS5 full-text search. No embeddings. No vector DB. No API costs for recall.
- Save: Auto-deduplicates (>80% word overlap → update instead of insert)
- Search: BM25 ranking via FTS5
MATCH - Recall: Agent automatically searches memory on every message
- Built-in tools: The LLM can
save_memory,search_memory,forget_memory
- Encrypted secrets: API keys encrypted with Fernet, key derived from your Mac's hardware UUID
- Command blocklist: Prevents
rm -rf /,mkfs,dd,shutdown, etc. - Path restriction: File tools restricted to workspace directory
- Audit log: All shell commands logged to
~/.antidote/audit.log - Timeout enforcement: Shell commands killed after 60s (configurable)
antidote # Run the bot (auto-setup if first time)
antidote setup # Run/re-run the setup wizard
./start.sh # Alternative launcher (creates venv if needed)Generated by the wizard at ~/.antidote/config.json:
{
"name": "Antidote",
"providers": {
"default": "openrouter",
"openrouter": { "model": "anthropic/claude-sonnet-4-20250514" },
"ollama": { "model": "llama3.2", "base_url": "http://localhost:11434" }
},
"memory": { "db_path": "~/.antidote/memory.db", "max_context_memories": 10 },
"safety": { "blocked_commands": ["rm -rf /", "mkfs", "dd if=", ...] }
}- Python 3.11+
- macOS (for hardware UUID encryption + launchd auto-restart)
- A Telegram account + bot token (free, 2 minutes via @BotFather)
- An OpenRouter API key (pay-per-use, most models under $0.01/message)
| Dependency | Purpose |
|---|---|
| LiteLLM | Unified API for 100+ LLM providers |
| python-telegram-bot | Async Telegram Bot API |
| aiosqlite | Async SQLite with FTS5 |
| cryptography | Fernet encryption for secrets |
| Rich | Beautiful terminal formatting |
| questionary | Interactive CLI prompts |
~3,000 lines · 31 files · 7 dependencies · 0 Docker containers
Built by Mark Kashef as the antidote to everything wrong with AI frameworks.