A barebones starter template for building a personal 24/7 AI assistant that runs on your machine and communicates via Telegram.
Jarvis is a personal AI agent that:
- Runs 24/7 as a background process
- Communicates through Telegram
- Uses Claude as its reasoning engine
- Orchestrates tasks via MCP servers (filesystem, browser, code sandbox, and more)
- Maintains conversation history and long-term memory
- Requires explicit approval for risky operations
This starter is intentionally simplified for clarity:
- Removed complex retry/event logic (kept the basics)
- Simplified error handling
- Removed production features (voice calls, smart home, job tracker, etc.)
- Streamlined MCP server setup (filesystem, playwright, sandbox, memory only)
- Minimal but functional scheduler and memory system
This is a working foundation β you can run it immediately after adding your API keys. Build additional features on top as needed.
main.py (entry point / orchestrator)
βββ PersonalAgent (Claude Agent SDK)
β βββ MCP Servers (filesystem, playwright, sandbox, memory)
β βββ Risk classification hook
β βββ Context loader (personality, skills, memory)
βββ TelegramBot (aiogram)
β βββ Handlers (/start, /task, /status, /model)
β βββ Approval flow (inline keyboard)
β βββ Message splitting
βββ TaskStore (Redis)
βββ Scheduler (basic cron)
βββ Memory system (ChromaDB for vector search)
- Python 3.12+
- Redis (local or Docker)
- Claude API key
- Telegram bot token
git clone <this-repo> jarvis
cd jarvis
# Install dependencies
uv sync --all-packages
# Or with pip
pip install -r requirements.txtCopy .env.example to .env and fill in your credentials:
cp .env.example .envThen edit .env:
ANTHROPIC_API_KEY=sk-ant-...
TELEGRAM_BOT_TOKEN=123456:ABC-DEF...
TELEGRAM_CHAT_ID=your_user_id
TELEGRAM_ALLOWED_USER_IDS=[your_user_id]
REDIS_URL=redis://localhost:6379Get your Telegram credentials:
- Bot Token: Create a bot via @BotFather, get the token
- Chat ID: Send a message to your bot, then visit
https://api.telegram.org/bot<TOKEN>/getUpdatesto see your user ID
Option A: Local (requires redis-server installed)
redis-serverOption B: Docker
docker run -d -p 6379:6379 redis:7-alpineuv run python main.pyYou should see:
INFO: redis_connected url=redis://localhost:6379
INFO: starting_agent model=claude-sonnet-4-6
INFO: telegram_bot_starting
Open Telegram and send a message to your bot. It should respond!
Send commands to your bot via Telegram:
-
/task <description> β Submit a task for the agent to complete
/task find me a recipe for chocolate chip cookies -
/status β View currently running tasks
/status -
/model <name> β Switch AI model (haiku, sonnet, opus)
/model opus -
Regular message β Chat with the agent
What's the weather like in NYC?
jarvis-starter/
βββ main.py # Entry point
βββ pyproject.toml # Root workspace config
βββ compose.yaml # Docker Compose (optional)
βββ .env.example # Environment template
βββ README.md # This file
βββ packages/
β βββ core/src/core/
β β βββ __init__.py
β β βββ agent.py # PersonalAgent (Claude Agent SDK wrapper)
β β βββ config.py # Settings (pydantic)
β β βββ context.py # ContextLoader (personality + skills)
β β βββ state.py # TaskStore + ConversationBuffer (Redis)
β β βββ risk.py # Risk classifier (2-tier)
β β βββ humanize.py # Human-readable tool descriptions
β β βββ logging.py # Structured logging
β βββ interfaces/src/interfaces/telegram/
β β βββ __init__.py
β β βββ bot.py # TelegramBot class
β β βββ handlers.py # Command handlers
β β βββ middleware.py # Auth middleware
β β βββ approval.py # Inline approval flow
β β βββ attachments.py # File downloads
β βββ mcp_servers/src/mcp_servers/
β β βββ __init__.py
β β βββ memory/server.py # Memory MCP server (ChromaDB)
β β βββ memory/__init__.py
β βββ pyproject.toml # Package workspace config
β βββ pyproject.toml (each package)
βββ tools/memory/
β βββ __init__.py
β βββ store.py # MemoryStore class
β βββ __main__.py # CLI (store/search/list)
βββ data/
β βββ agent_context/
β β βββ personality.md # Agent identity & tone
β β βββ schedules.md # Cron schedule entries
β β βββ memory/
β β β βββ preferences.md # User preferences (auto-written)
β β β βββ projects.md # Active projects (auto-written)
β β β βββ chat_history.md # Session summaries (auto-written)
β β β βββ journal.md # Task journal (auto-written)
β β βββ skills/
β β βββ _index.md # Skill registry
β β βββ _manager.md # Skill routing logic
β β βββ example-skill.md # Example skill definition
β βββ memory/chroma/ # Vector store (auto-created)
β βββ attachments/ # Downloaded files
βββ configs/
β βββ agent.yaml # Runtime configuration
β βββ risk_policy.yaml # Risk classification overrides
βββ tests/
βββ conftest.py # pytest fixtures
βββ unit/
βββ test_example.py # Example test
agent:
model: "claude-sonnet-4-6" # Primary model
max_turns: 50 # Max conversation turns
approval_timeout_seconds: 300 # How long to wait for approval
task_timeout_seconds: 600 # Task execution timeout
timezone: "America/New_York" # For scheduled tasks
workspace:
allowed_paths: # Paths the agent can access
- "/Users/YOUR_NAME/Documents"
- "/Users/YOUR_NAME/Downloads"
context_dir: "data/agent_context" # Where context files live
logging:
level: "INFO" # DEBUG, INFO, WARNING, ERROR
format: "json" # json or consoleDefine which operations require approval:
risk_overrides:
mcp__gmail__send_email: "approval" # Always ask before sending email
mcp__filesystem__write_file: "autonomous" # Auto-write files (careful!)Wraps the Claude Agent SDK with:
- MCP server configuration
- Risk classification hook (approve/deny decisions)
- Context loading (personality + skills + memory)
- Fallback handling (retries with different models)
Two-tier system:
- Autonomous: Safe operations (reading files, web search, code execution) β execute immediately
- Require-Approval: Risky operations (sending emails, deleting files) β ask user via Telegram inline keyboard
Override in configs/risk_policy.yaml to customize.
Handles:
- Command routing (/task, /status, /model, etc.)
- Approval flow (inline keyboard with Approve/Deny buttons)
- Message splitting (Telegram max 4096 chars)
- Auth middleware (allowlist user IDs)
Three levels:
- Conversation Buffer (Redis, TTL 1hr) β Recent chat history for context
- Chat History (file, auto-trimmed) β Session summaries (personality.md loads this)
- Vector Memory (ChromaDB) β Searchable summaries from past tasks
Use the memory CLI:
uv run python -m tools.memory store "summary text" --topics "topic1,topic2"
uv run python -m tools.memory search "what did I do about X?"
uv run python -m tools.memory list --last 10Define repeatable workflows in data/agent_context/skills/:
## Daily News Briefing
**Trigger:** Scheduled daily at 9 AM
**Steps:**
1. Search for tech news
2. Compile top stories
3. Send summary via Telegram
**Tools Required:** WebSearch, Telegram
**Tags:** autonomous, scheduled
**Composable With:** email-digestRegister in skills/_index.md for the agent to find and use them.
Edit packages/core/src/core/agent.py β _build_mcp_servers():
servers["my-server"] = {
"type": "stdio",
"command": "npx",
"args": ["-y", "@example/my-mcp-server"],
}Edit packages/interfaces/src/interfaces/telegram/handlers.py:
async def cmd_mycommand(message: Message, task_store: TaskStore) -> None:
# your handler logic
await message.answer("Result!")
def create_router(...):
router.message.register(cmd_mycommand, Command("mycommand"))Edit data/agent_context/personality.md β everything here loads into the system prompt.
After completing a task, use:
from tools.memory import MemoryStore
store = MemoryStore()
store.store(
"Fixed the deployment bug by rolling back schema migration",
topics=["devops", "database"],
files_touched=["migrations/001_fix.sql"],
)# All tests
uv run pytest tests/ -v
# Single test file
uv run pytest tests/unit/test_example.py -v
# With coverage
uv run pytest tests/ --cov=packages/| Variable | Required | Default | Purpose |
|---|---|---|---|
ANTHROPIC_API_KEY |
Yes | β | Claude API key |
TELEGRAM_BOT_TOKEN |
Yes | β | Telegram bot token |
TELEGRAM_CHAT_ID |
Yes | β | Your Telegram user ID |
TELEGRAM_ALLOWED_USER_IDS |
Yes | β | List of allowed user IDs (JSON) |
REDIS_URL |
No | redis://localhost:6379 |
Redis connection string |
CONFIG_PATH |
No | configs/agent.yaml |
Path to config file |
RISK_POLICY_PATH |
No | configs/risk_policy.yaml |
Path to risk policy file |
OPENAI_API_KEY |
No | β | For memory embeddings (optional) |
Redis isn't running. Start it:
redis-server # or docker run -d -p 6379:6379 redis:7-alpine- Check
TELEGRAM_CHAT_IDis correct (not bot ID) - Check bot token is valid
- Check logs:
uv run python main.py 2>&1 | grep -i error - Make sure your user ID is in
TELEGRAM_ALLOWED_USER_IDS
Increase approval_timeout_seconds or task_timeout_seconds in configs/agent.yaml.
Claude API is rate-limited or down. The agent will retry with a cheaper model (haiku). Check your API quota and billing.
Delete data/memory/chroma/ and restart β it will recreate the database.
- Personalize personality.md β Update identity, tone, and rules to match your preferences
- Add your first skill β Create a repeatable workflow in
data/agent_context/skills/ - Enable a new MCP server β Integrate Google Calendar, email, or custom tools
- Set up scheduled tasks β Add entries to
data/agent_context/schedules.md - Build context β Let the agent run and it will auto-populate preferences.md, projects.md, chat_history.md
- Claude Agent SDK subprocess model β Clean, isolated agent execution
- Local ChromaDB β No cloud vector DB dependency
- Redis for state β Task store, conversation buffer, approval flow
- Async/await throughout β Efficient, non-blocking operations
- Haiku fallback β Cheaper model for retries on API issues
This starter is provided as-is. Modify and extend freely.
- CLAUDE.md in the main repo β Full documentation of the production version
- tests/ β Example unit tests showing how to test each component
- Inline code comments β Each module explains its purpose and design
Happy building! π