This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Telegram bot providing remote access to Claude Code. Python 3.10+, built with Poetry, using python-telegram-bot for Telegram and claude-agent-sdk for Claude Code integration.
make dev # Install all deps (including dev)
make install # Production deps only
make run # Run the bot
make run-debug # Run with debug logging
make test # Run tests with coverage
make lint # Black + isort + flake8 + mypy
make format # Auto-format with black + isort
# Run a single test
poetry run pytest tests/unit/test_config.py -k test_name -v
# Type checking only
poetry run mypy srcClaudeIntegration (facade in src/claude/facade.py) wraps ClaudeSDKManager (src/claude/sdk_integration.py), which uses claude-agent-sdk with ClaudeSDKClient for async streaming. Session IDs come from Claude's ResultMessage, not generated locally.
Sessions auto-resume: per user+directory, persisted in SQLite.
Agentic mode (default, AGENTIC_MODE=true):
Telegram message -> Security middleware (group -3) -> Auth middleware (group -2)
-> Rate limit (group -1) -> MessageOrchestrator.agentic_text() (group 10)
-> ClaudeIntegration.run_command() -> SDK
-> Response parsed -> Stored in SQLite -> Sent back to Telegram
External triggers (webhooks, scheduler):
Webhook POST /webhooks/{provider} -> Signature verification -> Deduplication
-> Publish WebhookEvent to EventBus -> AgentHandler.handle_webhook()
-> ClaudeIntegration.run_command() -> Publish AgentResponseEvent
-> NotificationService -> Rate-limited Telegram delivery
Classic mode (AGENTIC_MODE=false): Same middleware chain, but routes through full command/message handlers in src/bot/handlers/ with 13 commands and inline keyboards.
Bot handlers access dependencies via context.bot_data:
context.bot_data["auth_manager"]
context.bot_data["claude_integration"]
context.bot_data["storage"]
context.bot_data["security_validator"]src/config/-- Pydantic Settings v2 config with env detection, feature flags (features.py), YAML project loader (loader.py)src/bot/handlers/-- Telegram command, message, and callback handlers (classic mode + project thread commands)src/bot/middleware/-- Auth, rate limit, security input validationsrc/bot/features/-- Git integration, file handling, quick actions, session exportsrc/bot/orchestrator.py-- MessageOrchestrator: routes to agentic or classic handlers, project-topic routingsrc/claude/-- Claude integration facade, SDK/CLI managers, session management, tool monitoringsrc/projects/-- Multi-project support:registry.py(YAML project config),thread_manager.py(Telegram topic sync/routing)src/storage/-- SQLite via aiosqlite, repository pattern (users, sessions, messages, tool_usage, audit_log, cost_tracking, project_threads)src/security/-- Multi-provider auth (whitelist + token), input validators (with optionaldisable_security_patterns), rate limiter, audit loggingsrc/events/-- EventBus (async pub/sub), event types, AgentHandler, EventSecurityMiddlewaresrc/api/-- FastAPI webhook server, GitHub HMAC-SHA256 + Bearer token authsrc/scheduler/-- APScheduler cron jobs, persistent storage in SQLitesrc/notifications/-- NotificationService, rate-limited Telegram delivery
5-layer defense: authentication (whitelist/token) -> directory isolation (APPROVED_DIRECTORY + path traversal prevention) -> input validation (blocks .., ;, &&, $(), etc.) -> rate limiting (token bucket) -> audit logging.
SecurityValidator blocks access to secrets (.env, .ssh, id_rsa, .pem) and dangerous shell patterns. Can be relaxed with DISABLE_SECURITY_PATTERNS=true (trusted environments only).
ToolMonitor validates Claude's tool calls against allowlist/disallowlist, file path boundaries, and dangerous bash patterns. Tool name validation can be bypassed with DISABLE_TOOL_VALIDATION=true.
Webhook authentication: GitHub HMAC-SHA256 signature verification, generic Bearer token for other providers, atomic deduplication via webhook_events table.
Settings loaded from environment variables via Pydantic Settings. Required: TELEGRAM_BOT_TOKEN, TELEGRAM_BOT_USERNAME, APPROVED_DIRECTORY. Key optional: ALLOWED_USERS (comma-separated Telegram IDs), ANTHROPIC_API_KEY, ENABLE_MCP, MCP_CONFIG_PATH.
Agentic platform settings: AGENTIC_MODE (default true), ENABLE_API_SERVER, API_SERVER_PORT (default 8080), GITHUB_WEBHOOK_SECRET, WEBHOOK_API_SECRET, ENABLE_SCHEDULER, NOTIFICATION_CHAT_IDS.
Security relaxation (trusted environments only): DISABLE_SECURITY_PATTERNS (default false), DISABLE_TOOL_VALIDATION (default false).
Multi-project topics: ENABLE_PROJECT_THREADS (default false), PROJECT_THREADS_MODE (private|group), PROJECT_THREADS_CHAT_ID (required for group mode), PROJECTS_CONFIG_PATH (path to YAML project registry), PROJECT_THREADS_SYNC_ACTION_INTERVAL_SECONDS (default 1.1, set 0 to disable pacing). See config/projects.example.yaml.
Output verbosity: VERBOSE_LEVEL (default 1, range 0-2). Controls how much of Claude's background activity is shown to the user in real-time. 0 = quiet (only final response, typing indicator still active), 1 = normal (tool names + reasoning snippets shown during execution), 2 = detailed (tool names with input summaries + longer reasoning text). Users can override per-session via /verbose 0|1|2. A persistent typing indicator is refreshed every ~2 seconds at all levels.
Voice transcription: ENABLE_VOICE_MESSAGES (default true), VOICE_PROVIDER (mistral|openai, default mistral), MISTRAL_API_KEY, OPENAI_API_KEY, VOICE_TRANSCRIPTION_MODEL. Provider implementation is in src/bot/features/voice_handler.py.
Feature flags in src/config/features.py control: MCP, git integration, file uploads, quick actions, session export, image uploads, voice messages, conversation mode, agentic mode, API server, scheduler.
All datetimes use timezone-aware UTC: datetime.now(UTC) (not datetime.utcnow()). SQLite adapters auto-convert TIMESTAMP/DATETIME columns to datetime objects via detect_types=PARSE_DECLTYPES. Model from_row() methods must guard fromisoformat() calls with isinstance(val, str) checks.
- Black (88 char line length), isort (black profile), flake8, mypy strict, autoflake for unused imports
- pytest-asyncio with
asyncio_mode = "auto" - structlog for all logging (JSON in prod, console in dev)
- Type hints required on all functions (
disallow_untyped_defs = true) - Use
datetime.now(UTC)notdatetime.utcnow()(deprecated)
Agentic mode commands: /start, /new, /status, /verbose, /repo. If ENABLE_PROJECT_THREADS=true: /sync_threads. To add a new command:
- Add handler function in
src/bot/orchestrator.py - Register in
MessageOrchestrator._register_agentic_handlers() - Add to
MessageOrchestrator.get_bot_commands()for Telegram's command menu - Add audit logging for the command
- Add handler function in
src/bot/handlers/command.py - Register in
MessageOrchestrator._register_classic_handlers() - Add to
MessageOrchestrator.get_bot_commands()for Telegram's command menu - Add audit logging for the command