A personal AI assistant with CLI, web, email, and Telegram channels. Routes messages to configurable AI providers (ollama, claude), manages persistent memory in an Obsidian vault, and integrates with Todoist, weather, Strava, and Obsidian daily notes. Uses uv for package management with Python 3.14.
tars is a conversational assistant that remembers things across sessions, manages your tasks, checks the weather, captures web pages, and writes to your daily notes. It stores memory in Obsidian markdown files so everything stays readable and editable outside of tars.
Channels:
- CLI — REPL with streaming, tab completion, and slash commands
- Web UI — browser-based chat with SSE streaming
- Email — IMAP polling + SMTP reply via Gmail, with slash commands in subject or body
- Telegram — bot polling with persistent reply keyboard and slash commands
Tools:
- Todoist — add, list, complete tasks via natural language
- Weather — current conditions and hourly forecasts (Open-Meteo)
- Memory — persistent facts and preferences in an Obsidian vault
- Daily notes — append thoughts to today's Obsidian journal entry
- Search — hybrid keyword + semantic search across all memory types, with windowed context retrieval
- Strava — activities, summaries, training analysis, HR zones, routes, and gear via Strava API
- Web read — fetch and extract text content from web pages for discussion
- Capture — save web pages to your Obsidian vault with AI summarization (context-aware when mid-conversation)
- MCP — extend with external tool servers via the Model Context Protocol (fetch, GitHub, filesystem, etc.)
Memory: Four-tier system (semantic, procedural, daily, episodic) stored as plain markdown in the Obsidian vault. Automatic fact extraction promotes good entries to permanent memory via /review. See docs/memory.md.
Multi-model routing: When TARS_MODEL_REMOTE is set, tars escalates tool-intent messages to the remote model and falls back on transient errors. See docs/routing.md.
Search: Hybrid FTS5 keyword + sqlite-vec KNN, fused with Reciprocal Rank Fusion. Query rewriting and HyDE for expanded retrieval. Two-pass context packing for automatic search on first message. See docs/search.md.
Scheduling: In-process scheduler for recurring tasks within long-lived processes, plus OS-level scheduling via launchd/systemd. See docs/scheduling.md.
MCP: Extend with external tool servers via the Model Context Protocol. Configured, not coded. See docs/mcp.md.
Feedback loop: /w flags bad responses, /r flags good ones, /review distills corrections into procedural rules, /tidy cleans up stale entries. See docs/memory.md.
[CLI / Web / Email / Telegram] → [conversation.py] → [core.py] → ollama / claude
↕
[tools.py] → todoist, weather, memory, notes, search, web, strava
↕ ↕
[memory.py] ← obsidian vault (TARS_MEMORY_DIR) [mcp.py] → external MCP servers
[notes.py] ← obsidian vault (TARS_NOTES_DIR)
[search.py] ← sqlite-vec + FTS5 (tars.db)
[router.py] → multi-model routing + fallback
- Providers: Claude (Anthropic API) or ollama (local models). Set via
TARS_MODEL_DEFAULT. - Routing: keyword pre-routing escalates to remote model on tool intent, falls back on errors. See docs/routing.md.
- Search: hybrid FTS5 + sqlite-vec KNN with RRF fusion, query rewriting, and two-pass context packing. See docs/search.md.
- Memory: four-tier system with automatic extraction and feedback loop. See docs/memory.md.
- Streaming: CLI and web UI stream responses token-by-token.
- Sessions: conversations are summarised and logged to the vault. Compaction keeps context manageable during long sessions.
# REPL
tars
# Single message
tars "what's the weather like?"
# Web UI
tars serve
# or: tars-serve
# Email channel
tars email
# or: tars-email
# Send daily brief via email
tars email-brief
# Telegram bot
tars telegram
# or: tars-telegram
# Send daily brief via Telegram
tars telegram-brief
# Schedule daily email brief
tars schedule add email-brief email-brief --hour 8 --minute 0
# Schedule vault reindex on file change
tars schedule add notes-reindex notes-index --watch "$TARS_NOTES_DIR"
# List installed schedules
tars schedule list
# Test-run a schedule (uses baked OS environment)
tars schedule test email-brief
# Remove a schedule
tars schedule remove email-brief
# Rebuild search index
tars index
# or: tars-index| Command | Description |
|---|---|
/todoist add <text> [--due D] [--project P] [--priority N] |
Add a task |
/todoist today |
List today's tasks |
/todoist upcoming [days] |
List upcoming tasks |
/todoist complete <ref> |
Complete a task |
/weather |
Current conditions |
/forecast |
Today's hourly forecast |
/memory |
Show persistent memory |
/remember <semantic|procedural> <text> |
Save to memory |
/note <text> |
Append to today's daily note |
/capture <url> [--raw] |
Capture web page to vault |
/search <query> |
Hybrid keyword + semantic search |
/sgrep <query> |
Keyword search (FTS5/BM25) |
/svec <query> |
Semantic search (vector KNN) |
/sessions |
List recent sessions |
/session <query> |
Search session logs |
/brief |
Daily digest (tasks + weather) |
/mcp |
List connected MCP servers and tools |
/stats |
Memory and index health |
/model |
Show active model configuration |
/w [note] |
Flag last response as wrong |
/r [note] |
Flag last response as good |
/review |
Review corrections and apply learnings |
/tidy |
Clean up memory (duplicates, junk) |
Slash commands work in the email subject line or body:
| Command | Description |
|---|---|
/todoist add <text> |
Add a task |
/todoist today |
List today's tasks |
/weather |
Current conditions |
/forecast |
Today's hourly forecast |
/memory |
Show persistent memory |
/remember <section> <text> |
Save to memory |
/note <text> |
Append to daily note |
/read <url> |
Fetch and return page content |
/capture <url> [--raw] |
Capture web page to vault |
Slash commands work in the bot chat. A persistent reply keyboard provides one-tap access to common commands.
| Command | Description |
|---|---|
/todoist add <text> |
Add a task |
/todoist today |
List today's tasks |
/weather |
Current conditions |
/forecast |
Today's hourly forecast |
/memory |
Show persistent memory |
/remember <section> <text> |
Save to memory |
/note <text> |
Append to daily note |
/capture <url> [--raw] |
Capture web page to vault |
/brief |
Daily briefing digest |
/search <query> |
Hybrid search over memory |
/find <query> |
Search personal notes vault |
/sessions |
List recent sessions |
/clear |
Reset conversation |
| Env var | Default | Purpose |
|---|---|---|
TARS_MODEL_DEFAULT |
claude:sonnet |
Primary model (provider:model) |
TARS_MODEL_REMOTE |
— | Remote model for tool calls (provider:model, explicit versions recommended; set to none to disable) |
TARS_MODEL_EMBEDDING |
qwen3-embedding:8b |
Embedding model for indexing and search |
TARS_MODEL_RETRIEVAL |
gemma3:4b |
Local model for query rewriting and HyDE |
TARS_ROUTING_POLICY |
tool |
Routing policy (only tool supported) |
TARS_MEMORY_DIR |
— | Path to tars Obsidian vault |
TARS_NOTES_DIR |
— | Path to personal Obsidian vault (daily notes, captures) |
TARS_MAX_TOKENS |
1024 |
Max tokens for Anthropic responses |
ANTHROPIC_API_KEY |
— | Required for Claude provider |
TARS_EMAIL_ADDRESS |
— | Gmail address for email channel |
TARS_EMAIL_PASSWORD |
— | Gmail app password |
TARS_EMAIL_ALLOW |
— | Comma-separated allowed sender addresses |
TARS_EMAIL_TO |
— | Recipient address for email brief |
TARS_EMAIL_POLL_INTERVAL |
60 |
Seconds between inbox checks |
TARS_TELEGRAM_TOKEN |
— | Telegram bot API token from BotFather |
TARS_TELEGRAM_ALLOW |
— | Comma-separated Telegram user IDs |
TARS_AUTO_EXTRACT |
true |
Enable automatic fact extraction on session save/compact |
TARS_API_TOKEN |
— | Optional bearer token for API auth |
TARS_SCHEDULES |
— | JSON array of scheduled tasks (alternative to schedules.json) |
TARS_MCP_SERVERS |
— | JSON object of MCP server configs (alternative to mcp_servers.json) |
TARS_OLLAMA_THINK |
false |
Enable thinking mode for qwen3 models |
TARS_STRAVA_CLIENT_ID |
— | Strava OAuth app client ID |
TARS_STRAVA_CLIENT_SECRET |
— | Strava OAuth app client secret |
DEFAULT_LAT / DEFAULT_LON |
— | Weather location coordinates |
Requires Python 3.14+ and uv.
git clone <repo> && cd tars
uv sync
cp .env.example .env # add your API keys and vault paths
tarsuv run python -m unittest discover -s tests -v