You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Claude Code Rust Telegram (CTM) is a bidirectional bridge between Claude Code CLI sessions and Telegram. It captures Claude Code hook events, forwards them to Telegram, and injects Telegram replies back into the CLI via tmux.
sequenceDiagram
participant CC as Claude Code
participant Hook as ctm hook
participant Socket as Socket Server
participant Bridge as Bridge
participant Bot as Telegram Bot
participant TG as Telegram
CC->>Hook: Hook event (stdin JSON)
Hook->>Hook: Parse HookEvent
Hook->>Hook: Add tmux metadata
Hook->>Socket: Connect + send NDJSON
Hook->>CC: Pass through (stdout)
Socket->>Bridge: mpsc::Receiver<BridgeMessage>
Bridge->>Bridge: Route by MessageType
alt SessionStart
Bridge->>Bridge: Create/reactivate session
Bridge->>Bot: Create forum topic
Bot->>TG: createForumTopic
TG-->>Bot: topic_id
Bridge->>Bot: Send start notification
else AgentResponse
Bridge->>Bot: Send formatted response
else ToolStart
Bridge->>Bridge: Summarize tool action
Bridge->>Bot: Send human-readable summary + Details button
else TurnComplete
Bridge->>Bridge: Check compaction state
else SendImage
Bridge->>Bridge: Validate file path
Bridge->>Bot: send_photo or send_document
Bot->>TG: sendPhoto/sendDocument (thread_id)
end
Bot->>TG: sendMessage (thread_id)
Loading
Telegram to CLI (Inbound)
sequenceDiagram
participant User as User (Phone)
participant TG as Telegram
participant Bot as Telegram Bot
participant Bridge as Bridge
participant INJ as InputInjector
participant TMUX as tmux
User->>TG: Send message in topic
TG->>Bot: getUpdates (long poll)
Bot->>Bridge: Update event
Bridge->>Bridge: Validate chat_id (Security #5)
Bridge->>Bridge: Find session by thread_id
alt Regular text
Bridge->>Bridge: Dedup check
Bridge->>INJ: inject(text)
INJ->>TMUX: send-keys -l "text"
INJ->>TMUX: send-keys Enter
else Photo / Document
Bridge->>Bridge: Download file via Bot API
Bridge->>Bridge: Save to /tmp/ctm-images/{uuid}.{ext}
Bridge->>Bridge: Set perms 0o600
Bridge->>INJ: inject("[Image/File from Telegram: path]")
INJ->>TMUX: send-keys -l notification
else "stop" / "esc"
Bridge->>INJ: send_key("Escape")
INJ->>TMUX: send-keys Escape
else "kill" / "ctrl-c"
Bridge->>INJ: send_key("Ctrl-C")
INJ->>TMUX: send-keys C-c
else "cc clear"
Bridge->>INJ: send_slash_command("/clear")
INJ->>TMUX: send-keys -l "/clear" Enter
end
Loading
Tool Approval Flow
sequenceDiagram
participant CC as Claude Code
participant Hook as ctm hook
participant Bridge as Bridge
participant DB as SQLite
participant Bot as Telegram Bot
participant User as User (Phone)
CC->>Hook: PreToolUse (stdin)
Hook->>Bridge: ToolStart message
Bridge->>DB: create_approval()
Bridge->>Bot: Send with inline keyboard
Bot->>User: [Approve] [Reject] [Abort]
User->>Bot: Click "Approve"
Bot->>Bridge: CallbackQuery
Bridge->>DB: resolve_approval("approved")
Bridge->>Bot: Edit message + answer query
Note over CC: Approval is non-blocking.<br/>Claude falls back to CLI<br/>if no response in 5 min.
erDiagram
sessions {
TEXT id PK
INTEGER chat_id
INTEGER thread_id
TEXT status
TEXT hostname
TEXT project_dir
TEXT tmux_target
TEXT tmux_socket
TEXT started_at
TEXT last_activity
}
pending_approvals {
TEXT id PK
TEXT session_id FK
TEXT prompt
TEXT status
TEXT created_at
TEXT expires_at
}
sessions ||--o{ pending_approvals : "has"