Skip to content

gavraq/telegram-claude-agent

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Telegram Claude Agent System

A two-component system that enables Telegram access to Claude Agent SDK projects. Messages flow from Telegram through a gateway (on Raspberry Pi/Docker) to an agent service (on Mac/server) that executes Claude queries.

Architecture

┌─────────────────────┐
│    Telegram User    │
│  (sends messages)   │
└──────────┬──────────┘
           │
           ▼
┌─────────────────────────────────────────┐
│       Docker Host (e.g., Raspberry Pi)  │
│              telegram-gateway           │
│                                         │
│  • Receives Telegram messages           │
│  • Manages user sessions (SQLite)       │
│  • Forwards queries via HTTPS           │
│  • Returns responses to Telegram        │
│                                         │
│  Commands:                              │
│  /start, /help, /status, /setcwd,       │
│  /reset, /health                        │
└──────────┬──────────────────────────────┘
           │
           │ HTTPS (via reverse proxy)
           │
           ▼
┌─────────────────────────────────────────┐
│         Mac / Server                    │
│         telegram-agent                  │
│                                         │
│  • FastAPI service (port 8095)          │
│  • Wraps Claude Agent SDK               │
│  • Project autodiscovery                │
│  • Runs in any working directory        │
│                                         │
│  Endpoints:                             │
│  GET /health, GET /project-info,        │
│  POST /query, POST /scheduled-job       │
└──────────┬──────────────────────────────┘
           │
           ▼
┌─────────────────────────────────────────┐
│         Claude Agent SDK                │
│                                         │
│  • Executes queries in project context  │
│  • Uses .claude/ configuration          │
│  • Runs skills and tools                │
│  • Maintains conversation sessions      │
└─────────────────────────────────────────┘

Components

1. Agent Service (/agent)

FastAPI service that wraps the Claude Agent SDK. Receives HTTP requests and executes Claude queries in the specified working directory.

Key Features:

  • Project autodiscovery - detects .claude/agents/ and loads appropriate system prompt
  • Session resume support - maintains conversation history
  • API key authentication
  • Automatic orchestrator detection
  • Scheduled job execution - accepts jobs from the standalone cron-scheduler service
  • Configurable model and max_turns per request

Endpoints:

Endpoint Method Description
/health GET Health check
/project-info GET Get project configuration info
/query POST Execute Claude Agent query (from Telegram gateway)
/scheduled-job POST Execute scheduled job (from cron-scheduler)

Source Files:

  • main.py - FastAPI application and endpoints (QueryRequest/Response, ScheduledJobRequest/Response)
  • runner.py - Claude SDK query execution (supports model override: haiku/sonnet/opus, max_turns)
  • project.py - Project autodiscovery logic

2. Gateway Bot (/gateway)

Telegram bot that receives messages and forwards them to the agent service.

Key Features:

  • Per-user sessions stored in SQLite
  • Custom working directory per user
  • Automatic session resume

Commands:

Command Description
/start Welcome message and setup
/help Show available commands
/status Show current session info
/setcwd <path> Set working directory for agent
/reset Clear conversation history
/health Check agent service status

Source Files:

  • bot.py - Telegram bot handlers
  • session.py - SQLite session management
  • client.py - HTTP client for agent service

Quick Start

Prerequisites

  1. Telegram Bot Token - Get from @BotFather
  2. Machine with Claude Agent SDK - Installed globally via npm (npm install -g @anthropic-ai/claude-code)
  3. Docker host - For the gateway (Raspberry Pi, VPS, etc.)

Step 1: Deploy Agent Service

cd agent

# Install dependencies
uv sync

# Configure environment
cp .env.example .env
# Edit .env to set AGENT_API_KEY

# Run the server
uv run telegram-agent

The server runs on http://0.0.0.0:8095.

Step 2: Configure as macOS Service (Optional)

  1. Copy and customize the plist template:
cp agent/com.example.telegram-agent.plist.template \
   ~/Library/LaunchAgents/com.yourdomain.telegram-agent.plist
  1. Edit the plist and replace placeholders:

    • {{PATH_TO_TELEGRAM_AGENT}} → Your agent directory path (e.g., /Users/yourname/projects/telegram/agent)
    • com.yourdomain.telegram-agent → Your preferred label
  2. Load the service:

launchctl load ~/Library/LaunchAgents/com.yourdomain.telegram-agent.plist

Step 3: Configure Reverse Proxy (Production)

Expose the agent service via HTTPS using Nginx, Caddy, or a cloud proxy:

Example Nginx configuration:

server {
    listen 443 ssl;
    server_name telegram-agent.yourdomain.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://localhost:8095;
        proxy_read_timeout 300s;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Step 4: Deploy Gateway

# Copy files to your Docker host
scp -r gateway user@your-docker-host:~/telegram-gateway

# SSH to the host
ssh user@your-docker-host

# Configure
cd ~/telegram-gateway
cp .env.example .env
# Edit .env with:
# - TELEGRAM_BOT_TOKEN (from BotFather)
# - AGENT_URL (your HTTPS endpoint)
# - AGENT_API_KEY (same as agent service)
# - DEFAULT_CWD (default project path on agent machine)

# Build and run
docker-compose up -d

Step 5: Test

  1. Open Telegram and find your bot
  2. Send /start
  3. Send a message like "Hello!"

Configuration

Agent Service (.env)

# API key for authenticating requests (required for production)
AGENT_API_KEY=your-secure-random-key-here

# Optional: Server binding
HOST=0.0.0.0
PORT=8095

Gateway Bot (.env)

# Telegram Bot Token from @BotFather
TELEGRAM_BOT_TOKEN=your-telegram-bot-token

# URL to the telegram-agent service (use HTTPS in production)
AGENT_URL=https://telegram-agent.yourdomain.com

# API key matching the agent service
AGENT_API_KEY=your-secure-api-key

# Default working directory for new users
DEFAULT_CWD=/path/to/your/default/project

Multi-Project Support

Users can switch between projects using /setcwd:

/setcwd /path/to/project-a
/setcwd /path/to/project-b

The agent service automatically detects project configuration:

  1. Orchestrator projects: Looks for *-engine.md or *-orchestrator.md in .claude/agents/
  2. Single-agent projects: Uses first agent found in .claude/agents/
  3. Generic projects: No special configuration, uses default Claude behavior

Session Management

Each Telegram user gets their own session:

  • session_id: Links to Claude conversation history (enables resume)
  • cwd: Working directory for agent queries
  • verbose: Show/hide tool call details

Sessions are stored in SQLite at /app/data/sessions.db in the gateway container.

Troubleshooting

Check Gateway Logs

docker logs telegram-gateway --tail 50

Check Agent Logs (if using launchd)

tail -f /tmp/telegram-agent.log
tail -f /tmp/telegram-agent.err

Health Check

# Local
curl http://localhost:8095/health

# Via HTTPS
curl https://telegram-agent.yourdomain.com/health

Restart Services

macOS (launchd):

launchctl stop com.yourdomain.telegram-agent
launchctl start com.yourdomain.telegram-agent

Docker:

docker restart telegram-gateway

Port Already in Use (Mac)

kill $(lsof -t -i :8095)
launchctl start com.yourdomain.telegram-agent

Reset All Sessions

# On Docker host
rm ~/telegram-gateway/data/sessions.db
docker restart telegram-gateway

Common Issues and Fixes

Issue: 502 Bad Gateway

Symptom: Telegram bot responds with "502 Bad Gateway" error.

Cause: Nginx Proxy Manager (or your reverse proxy) cannot reach the telegram-agent on the Mac.

Diagnosis:

# Check NPM error log for the telegram proxy host
ssh pi@<PI_IP> "docker exec nginx-proxy tail -20 /data/logs/proxy-host-<N>_error.log"

# Look for "connect() failed" or "No route to host" errors

Fixes:

  1. Verify Mac IP address hasn't changed:

    # On Mac
    ipconfig getifaddr en0
  2. Update NPM proxy host via web UI (http://<PI_IP>:81):

    • Edit the telegram subdomain proxy host
    • Update "Forward Hostname/IP" to current Mac IP
    • Save
  3. Reload nginx config:

    ssh pi@<PI_IP> "docker exec nginx-proxy nginx -s reload"
  4. Verify connectivity from Pi to Mac:

    ssh pi@<PI_IP> "curl -s http://<MAC_IP>:8095/health"

Issue: 404 Not Found on /query

Symptom: Gateway logs show 404 Not Found for /query endpoint.

Cause: The agent returns 404 when the cwd (working directory) doesn't exist on the Mac.

Diagnosis:

# Check what cwd the gateway is sending
ssh pi@<PI_IP> "docker exec telegram-gateway python3 -c \"
import sqlite3
conn = sqlite3.connect('/app/data/sessions.db')
c = conn.cursor()
c.execute('SELECT user_id, session_id, cwd FROM sessions')
print(c.fetchall())
\""

Fixes:

  1. If the cwd path is old/wrong, delete the stale session:

    ssh pi@<PI_IP> "docker exec telegram-gateway python3 -c \"
    import sqlite3
    conn = sqlite3.connect('/app/data/sessions.db')
    c = conn.cursor()
    c.execute('DELETE FROM sessions WHERE user_id=<YOUR_TELEGRAM_USER_ID>')
    conn.commit()
    print('Session deleted')
    \""
  2. Update DEFAULT_CWD in gateway .env if the default project path changed:

    ssh pi@<PI_IP> "cat ~/docker/telegram-gateway/.env | grep DEFAULT_CWD"
    # If wrong, update it:
    ssh pi@<PI_IP> "sed -i 's|DEFAULT_CWD=.*|DEFAULT_CWD=/correct/path/to/project|' ~/docker/telegram-gateway/.env"
  3. Recreate the container (restart alone won't pick up .env changes!):

    ssh pi@<PI_IP> "cd ~/docker/telegram-gateway && docker-compose down && docker-compose up -d"
  4. Verify the container has the new env value:

    ssh pi@<PI_IP> "docker exec telegram-gateway python3 -c \"import os; print('DEFAULT_CWD:', os.getenv('DEFAULT_CWD'))\""

⚠️ Important: The /reset command in Telegram only clears the session_id, NOT the cwd. If the cwd is wrong, you must manually delete the session from the database.


Issue: 500 Internal Server Error

Symptom: Gateway logs show 500 Internal Server Error for /query.

Cause: The agent service crashed or Claude SDK failed.

Diagnosis:

# Check agent error logs on Mac
tail -50 /tmp/telegram-agent.err

Common causes:

  • Session ID refers to a conversation that no longer exists
  • Claude SDK subprocess failed
  • Project configuration error

Fixes:

  1. Clear the session (forces new conversation):

    ssh pi@<PI_IP> "docker exec telegram-gateway python3 -c \"
    import sqlite3
    conn = sqlite3.connect('/app/data/sessions.db')
    c = conn.cursor()
    c.execute('DELETE FROM sessions WHERE user_id=<YOUR_TELEGRAM_USER_ID>')
    conn.commit()
    \""
  2. Restart the agent service (clears any stale state):

    # On Mac
    launchctl bootout gui/$(id -u)/com.gavinslater.telegram-agent
    launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.gavinslater.telegram-agent.plist

Issue: Agent service running old code after path change

Symptom: Errors reference old file paths in tracebacks.

Cause: Python process started before code was moved/updated.

Diagnosis:

# Check when process started
ps aux | grep telegram_agent

# Check what paths are in the traceback
tail -30 /tmp/telegram-agent.err

Fix: Fully restart the launchd service:

# bootout + bootstrap is required, not just kickstart
launchctl bootout gui/$(id -u)/com.gavinslater.telegram-agent
sleep 2
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.gavinslater.telegram-agent.plist

Quick Diagnostic Checklist

When Telegram bot stops working, run through this checklist:

# 1. Is the agent running on Mac?
curl -s http://localhost:8095/health

# 2. Can Pi reach the agent directly?
ssh pi@<PI_IP> "curl -s http://<MAC_IP>:8095/health"

# 3. Can Pi reach agent via NPM/HTTPS?
ssh pi@<PI_IP> "curl -s https://telegram.yourdomain.com/health"

# 4. What's in the gateway session for your user?
ssh pi@<PI_IP> "docker exec telegram-gateway python3 -c \"
import sqlite3
conn = sqlite3.connect('/app/data/sessions.db')
c = conn.cursor()
c.execute('SELECT * FROM sessions')
for row in c.fetchall(): print(row)
\""

# 5. What's the DEFAULT_CWD in the running container?
ssh pi@<PI_IP> "docker exec telegram-gateway python3 -c \"import os; print(os.getenv('DEFAULT_CWD'))\""

# 6. Check recent gateway errors
ssh pi@<PI_IP> "docker logs telegram-gateway 2>&1 | grep -E '(ERROR|error|404|500|502)' | tail -10"

# 7. Check recent agent errors
tail -20 /tmp/telegram-agent.err

Network Requirements

From To Port Protocol
Internet Gateway Host 443 HTTPS (Telegram polling)
Gateway Agent 8095 HTTP (or HTTPS via proxy)
Agent Anthropic API 443 HTTPS

Security Considerations

  1. API Key Authentication: Both services use shared API key
  2. HTTPS: Use a reverse proxy with TLS certificates
  3. Working Directory Validation: Agent validates CWD exists
  4. Firewall: Restrict agent port to gateway IP only if possible

Project Structure

telegram/
├── README.md                 # This file
├── agent/                    # Agent service (runs on Mac/server)
│   ├── pyproject.toml
│   ├── Dockerfile
│   ├── docker-compose.yml
│   ├── .env.example
│   ├── .gitignore
│   ├── com.example.telegram-agent.plist.template  # macOS launchd template
│   └── src/telegram_agent/
│       ├── __init__.py
│       ├── main.py          # FastAPI application
│       ├── runner.py        # Claude SDK execution
│       └── project.py       # Project autodiscovery
├── gateway/                  # Gateway bot (runs on Docker host)
│   ├── pyproject.toml
│   ├── Dockerfile
│   ├── docker-compose.yml
│   ├── .env.example
│   ├── .gitignore
│   └── src/telegram_gateway/
│       ├── __init__.py
│       ├── bot.py           # Telegram bot
│       ├── session.py       # SQLite sessions
│       └── client.py        # HTTP client
└── docs/                     # Additional documentation

Cron Scheduler Integration

The agent service also accepts scheduled job requests from the standalone cron-scheduler service (/Volumes/DockSSD/projects/scheduler/), which runs in Docker on the Raspberry Pi alongside the Telegram gateway.

┌─────────────────────────────────────────────────────┐
│  Raspberry Pi (Docker)                              │
│                                                     │
│  ┌──────────────────┐  ┌────────────────────────┐  │
│  │ telegram-gateway  │  │ cron-scheduler         │  │
│  │ (Telegram bot)    │  │ (port 8092, generic)   │  │
│  └────────┬─────────┘  └──────────┬─────────────┘  │
│           │                       │                  │
└───────────┼───────────────────────┼──────────────────┘
            │                       │
            │ POST /query           │ POST /scheduled-job
            ▼                       ▼
┌─────────────────────────────────────────────────────┐
│  Mac (telegram-agent, port 8095)                    │
│  Wraps Claude Agent SDK                             │
└─────────────────────────────────────────────────────┘

Scheduled Job Request:

{
  "project": "/Volumes/DockSSD/projects/riskagents",
  "prompt": "Run a regulatory monitoring scan...",
  "model": "sonnet",
  "max_turns": 15,
  "timeout_seconds": 600,
  "job_name": "weekly-regulatory-scan"
}

The /scheduled-job endpoint creates a fresh Claude session each time (no resume) and returns structured results including status, duration, cost, and skills used — which the scheduler logs for monitoring.

The scheduler has its own web dashboard at scheduler.gavinslater.co.uk for managing jobs.

Future Enhancements

  • File attachment support (send generated files via Telegram)
  • Inline keyboards for interactive workflows
  • Multiple registered projects with friendly names
  • Streaming responses with message editing
  • Voice message transcription

License

MIT License - See LICENSE file for details.

About

Telegram bot gateway for Claude Agent SDK projects

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors