- Go 97.3%
- Shell 2.5%
- Makefile 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Implements Phase 3 feature with full Model Context Protocol (MCP) support for Google Calendar access. Features: - Complete MCP protocol client (JSON-RPC over stdio) - Google Calendar tool integration via google-calendar-mcp server - Tool calling support in Ollama client with format conversion - Multi-round tool execution in orchestrator - OAuth 2.0 authentication flow - Privacy-first: all calendar data processed locally Architecture: - internal/mcp/ - MCP protocol implementation - internal/mcp/tools/ - Calendar tool wrappers - internal/mcpmanager/ - MCP lifecycle and execution management - Enhanced LLM interface with tool calling support - Ollama-specific tool call format handling Tools available: - list_calendar_events - Query calendar by date range - create_calendar_event - Schedule new events - search_calendar_events - Find events by keyword - get_current_time - Time context for queries Documentation: - docs/google-calendar-setup.md - Complete OAuth setup guide - docs/mcp-architecture.md - Technical architecture deep-dive - Updated README with calendar integration section Security: - OAuth credentials stored locally only - Tool filtering (read + create only by default) - Process isolation for MCP server - Flexible argument parsing for LLM compatibility 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
| cmd | ||
| docs | ||
| internal | ||
| observability | ||
| .env.example | ||
| .gitignore | ||
| .golangci.yml | ||
| assistant | ||
| auth-calendar.sh | ||
| docker-compose.yml | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
| setup-google-auth.sh | ||
Mimir
Your personal Mimir — knowledge, wisdom, and conversation. All local, all private.
Overview
Mimir is a privacy-first conversational AI that runs entirely on your machine. Chat with it via Telegram, powered by local LLMs (Ollama), with full conversation history, observability, and zero external data sharing.
Key Features:
- 🔒 100% Local — No data sent to external LLM providers
- 💬 Telegram Interface — Natural chat experience with long polling (no webhooks)
- 🧠 Ollama-Powered — Swap models freely (llama3.1, qwen2.5, DeepSeek, etc.)
- 📊 Full Observability — Prometheus metrics, Grafana dashboards, structured logs via Loki
- 🛡️ User Allowlist — Only authorized Telegram users can interact
- 🔄 Conversation Memory — PostgreSQL persistence with configurable history window
- ⚡ Circuit Breakers — Graceful degradation on Telegram or Ollama failures
Architecture
┌─────────────────┐
│ Telegram App │ (You)
└────────┬────────┘
│ Long Polling (HTTPS)
↓
┌────────────────────────────────┐
│ Mimir (Go) │
│ ┌──────────────────────────┐ │
│ │ Telegram Poller │ │
│ │ Orchestrator │ │
│ │ LLM Client (Ollama) │ │
│ │ Observability │ │
│ └──────────────────────────┘ │
└───┬────────────────────────┬───┘
│ │
↓ ↓
┌─────────────┐ ┌──────────────┐
│ PostgreSQL │ │ Ollama │
│ + pgvector │ │ (Local LLM) │
└─────────────┘ └──────────────┘
┌──────────────────────────────────┐
│ Observability Stack (Docker) │
│ Prometheus │ Grafana │ Loki │
└──────────────────────────────────┘
Core Principles:
- No inbound network connections (polling only)
- LLM has no internet access
- All tool calls are deterministic and auditable
- Circuit breakers prevent cascading failures
Prerequisites
| Requirement | Version | Purpose |
|---|---|---|
| Go | 1.24.3+ | Build and run the assistant |
| Docker | Latest | PostgreSQL + observability stack |
| Ollama | Latest | Local LLM runtime |
| Telegram Bot Token | — | Create via @BotFather |
| Your Telegram User ID | — | Get from @userinfobot |
Supported Platforms: macOS (Apple Silicon tested), Linux
Quick Start
1. Clone and Configure
git clone https://github.com/fandangolas/mimir.git
cd mimir
cp .env.example .env
# Edit .env with your Telegram bot token and user ID
2. Pull an Ollama Model
ollama pull llama3.1
# Or: ollama pull qwen2.5
3. Start Infrastructure
make up
# Starts: PostgreSQL, Prometheus, Grafana, Loki, Promtail
4. Run the Assistant
make run
5. Chat on Telegram
Open your bot on Telegram, send /start, and start chatting!
RAG: Long-Term Memory (Optional)
By default, Mimir remembers only the last 20 messages. RAG (Retrieval-Augmented Generation) gives Mimir true long-term memory, allowing it to remember conversations from weeks, months, or even years ago.
How RAG Works
RAG uses embeddings (numerical representations of text) to search your entire conversation history semantically:
You (3 months ago): "I'm allergic to peanuts"
You (today): "Recommend a restaurant"
Mimir (with RAG): "I'll suggest places with allergy-friendly menus since you have a peanut allergy" ✅
Without RAG, Mimir would have forgotten the allergy mention.
Enabling RAG
Step 1: Pull the embedding model
ollama pull nomic-embed-text
Step 2: Backfill existing messages (if you have chat history)
make build
./bin/backfill-embeddings
This generates embeddings for all existing messages. Progress is logged:
INFO starting backfill total_messages=1500
INFO progress processed=100 total=1500 remaining=1400 percent=6.7%
...
INFO backfill summary total_messages=1500 processed=1500 errors=0 success_rate=100.0%
Step 3: Enable RAG in .env
RAG_ENABLED=true
Step 4: Restart Mimir
make run
New messages will automatically get embeddings generated in the background.
What RAG Gives You
- 🧠 Semantic search: Finds conceptually similar conversations ("anxious" matches "worried", "stressed")
- 📅 Long-term memory: Remembers facts from months/years ago
- 🎯 Hybrid search: Combines semantic similarity + keyword matching + recency
- ⚡ Fast: Sub-second search even with 10,000+ messages
- 💾 Efficient: ~200 MB storage for 5 years of conversations
RAG Architecture
See docs/rag-architecture.md for:
- Complete technical architecture
- Glossary explaining embeddings, vectors, hybrid search
- Performance tuning guide
- Storage and performance estimates
Google Calendar Integration (Optional)
Mimir can integrate with your Google Calendar via the Model Context Protocol (MCP), allowing it to:
- View and search calendar events
- Create new events
- Check free/busy availability
- Provide time-aware responses
Setup: See docs/google-calendar-setup.md for complete instructions.
Quick start:
- Create Google Cloud project and OAuth credentials
- Enable MCP in
.env:MCP_ENABLED=true GOOGLE_OAUTH_CREDENTIALS=/path/to/gcp-oauth.keys.json - Start Mimir and complete OAuth flow
- Ask: "What's on my calendar today?"
All calendar data stays local. No external LLM providers see your calendar.
Configuration
All configuration is via environment variables (loaded from .env or system environment):
| Variable | Required | Default | Description |
|---|---|---|---|
TELEGRAM_BOT_TOKEN |
✅ | — | Telegram bot token from @BotFather |
ALLOWED_USER_IDS |
✅ | — | Comma-separated Telegram user IDs (e.g., 123456789,987654321) |
DATABASE_URL |
✅ | — | PostgreSQL connection string (default in .env.example works with Docker Compose) |
OLLAMA_BASE_URL |
❌ | http://localhost:11434 |
Ollama API URL |
OLLAMA_MODEL |
❌ | llama3.1 |
Model name (must support tool calling) |
LOG_LEVEL |
❌ | info |
Logging level: debug, info, warn, error |
LOG_DIR |
❌ | logs |
Directory for daily log files (tailed by Promtail) |
CONVERSATION_WINDOW |
❌ | 20 |
Number of recent messages sent to LLM |
METRICS_ADDR |
❌ | :9090 |
Prometheus metrics endpoint |
RAG (Long-Term Memory) Configuration
| Variable | Required | Default | Description |
|---|---|---|---|
RAG_ENABLED |
❌ | false |
Enable RAG for long-term conversational memory |
EMBEDDING_MODEL |
❌ | nomic-embed-text |
Ollama embedding model (768 dimensions) |
RAG_RETRIEVED_COUNT |
❌ | 5 |
Number of messages to retrieve from history |
RAG_RECENT_COUNT |
❌ | 10 |
Number of recent messages to include |
RAG_MIN_SIMILARITY |
❌ | 0.5 |
Minimum cosine similarity threshold (0-1) |
RAG_WEIGHT_SEMANTIC |
❌ | 0.5 |
Semantic similarity weight in hybrid search |
RAG_WEIGHT_KEYWORD |
❌ | 0.3 |
Keyword matching weight in hybrid search |
RAG_WEIGHT_RECENCY |
❌ | 0.2 |
Recency boost weight in hybrid search |
RAG_RECENCY_DECAY_DAYS |
❌ | 30 |
Days for recency score decay |
Note: Weights must sum to 1.0. See RAG Architecture for details.
Observability
Grafana Dashboards
Open http://localhost:3000 (login: admin / admin)
Pre-provisioned dashboard: Mimir
Metrics tracked:
- Messages received, processed (success/error), unauthorized attempts
- LLM latency (p50/p95/p99 + heatmap)
- Telegram send errors
- Message processing rate over time
RAG metrics (if enabled):
- RAG searches performed (success/error/fallback)
- Hybrid search latency
- Number of messages retrieved per query
- Context token usage
- Embedding generation latency and errors
Logs
Query structured logs in Grafana → Explore → Loki:
{job="mimir"}
Filter by correlation ID:
{job="mimir"} |= "123456-789"
Logs include:
correlation_id— unique per message (chat_id-message_id)chat_id— Telegram chat identifier- Structured fields for errors, latency, etc.
Metrics Endpoint
Raw Prometheus metrics: http://localhost:9090/metrics
Development
Build
make build
# Binary output: ./bin/assistant
Run Tests
make test
Run Linter
make lint
# Requires golangci-lint installed
Project Structure
mimir/
├── cmd/assistant/ # Main entry point
├── internal/
│ ├── config/ # Configuration loading
│ ├── telegram/ # Telegram bot client + poller
│ ├── orchestrator/ # Message flow coordinator
│ ├── llm/ollama/ # Ollama LLM client
│ ├── store/ # PostgreSQL access + migrations
│ └── observability/ # Logging, metrics, tracing
├── observability/ # Prometheus, Grafana, Loki configs
└── docs/ # Architecture documentation
Security
User Allowlist
Only Telegram users listed in ALLOWED_USER_IDS can send messages. Unauthorized attempts are:
- Silently dropped
- Logged as warnings
- Tracked in Prometheus (
assistant_unauthorized_messages_total)
Circuit Breakers
- Ollama: Opens after 3 consecutive failures (30s cooldown)
- Telegram: Opens after 5 consecutive send failures (10s cooldown)
Data Privacy
- No data sent to external LLM providers
- OAuth tokens (future: Google Calendar/Drive) encrypted at rest
- No personal data in logs (only correlation IDs)
Why "Mimir"?
In Norse mythology, Mimir was renowned for his knowledge and wisdom. He advised Odin, the Allfather, serving as a counselor and source of insight.
In God of War (2018), Mimir is portrayed as Kratos's companion — a disembodied head carried everywhere, offering guidance, lore, and witty commentary. This project channels that spirit: a personal, ever-present advisor who's always ready with an answer.
Unlike cloud AI assistants, Mimir stays with you, runs locally, and never shares your conversations with anyone. With RAG-powered long-term memory, Mimir truly remembers your conversations—making it a genuine personal assistant that grows wiser over time.
Roadmap
Phase 1 & 2: ✅ Complete
- Telegram ↔ LLM conversation
- Full observability stack
- User access control
Phase 2.5: ✅ Complete
- RAG (Retrieval-Augmented Generation) for long-term memory
- Hybrid search (semantic + keyword + recency)
- Embedding generation and backfill tools
- pgvector integration with HNSW indexes
Phase 3: 🚧 In Progress
- ✅ Google Calendar integration via MCP - Setup Guide
- Google Drive RAG (document search)
- Scheduled reminders
Phase 4: Pending
- Cloud deployment (VPS/AWS)
- Automated backups
See docs/development-phases.md and docs/rag-architecture.md for details.
Troubleshooting
"DATABASE_URL is required"
Ensure .env file exists and contains DATABASE_URL. Run cp .env.example .env if missing.
"model does not support native tool calling"
Switch to a supported model: llama3.1, llama3.2, qwen2.5, etc. Update OLLAMA_MODEL in .env.
Bot doesn't respond on Telegram
- Check
make runlogs for errors - Verify your Telegram user ID is in
ALLOWED_USER_IDS - Confirm Ollama is running:
ollama list
Grafana shows no data
- Wait 30s for first scrape
- Verify Prometheus is scraping: http://localhost:9091/targets
- Check app is exposing metrics:
curl localhost:9090/metrics
Contributing
This is a personal project, but suggestions are welcome via GitHub Issues.
Development Setup
- Fork and clone
- Run
make upto start dependencies - Run
make testbefore committing - Follow conventional commit format:
feat:,fix:,docs:, etc.
License
This project is licensed under the MIT License.
You are free to use, modify, and distribute this software in accordance with the terms of the license.
Acknowledgments
Built with:
- Ollama — Local LLM runtime
- Telegram Bot API — Chat interface
- Prometheus + Grafana — Observability
- Loki — Log aggregation
- pgvector — PostgreSQL vector extension (future RAG)
Inspired by the local-first and privacy-first software movement, and by Mimir's wisdom in Norse mythology.