{"id":45197257,"url":"https://github.com/laveez/cctg","last_synced_at":"2026-02-20T13:01:17.782Z","repository":{"id":339405713,"uuid":"1161753932","full_name":"laveez/cctg","owner":"laveez","description":"Claude Code Telegram Gate — approve Claude's tool calls from your phone","archived":false,"fork":false,"pushed_at":"2026-02-19T14:27:58.000Z","size":18,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-19T17:54:41.124Z","etag":null,"topics":["claude-code","cli","hooks","nodejs","permissions","telegram","telegram-bot"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/laveez.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-19T13:33:02.000Z","updated_at":"2026-02-19T14:28:02.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/laveez/cctg","commit_stats":null,"previous_names":["laveez/cctg"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/laveez/cctg","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laveez%2Fcctg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laveez%2Fcctg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laveez%2Fcctg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laveez%2Fcctg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/laveez","download_url":"https://codeload.github.com/laveez/cctg/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laveez%2Fcctg/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29651964,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-20T09:27:29.698Z","status":"ssl_error","status_checked_at":"2026-02-20T09:26:12.373Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["claude-code","cli","hooks","nodejs","permissions","telegram","telegram-bot"],"created_at":"2026-02-20T13:01:16.718Z","updated_at":"2026-02-20T13:01:17.770Z","avatar_url":"https://github.com/laveez.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# cctg\n\n**Claude Code Telegram Gate**\n\nControl Claude Code from your phone via Telegram — approve tool calls, answer questions, and send follow-up instructions.\n\n[![npm](https://img.shields.io/npm/v/cctg?style=flat-square)](https://www.npmjs.com/package/cctg)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](LICENSE)\n[![Node.js 18+](https://img.shields.io/badge/Node.js-18%2B-brightgreen?style=flat-square)](https://nodejs.org)\n[![Zero Dependencies](https://img.shields.io/badge/dependencies-0-brightgreen?style=flat-square)](#)\n\n\u003c/div\u003e\n\n---\n\nStart a task, walk away, and keep steering Claude from your phone. cctg hooks into Claude Code's event system to give you full remote control:\n\n- **Tool approvals** — approve or deny commands, file edits, and other tool calls\n- **Question answering** — when Claude asks a clarifying question, pick an option from Telegram\n- **Continuation** — when Claude finishes, send your next instruction from Telegram\n\n```mermaid\nsequenceDiagram\n    participant C as Claude Code\n    participant H as cctg hooks\n    participant T as Telegram\n    participant U as You (phone)\n\n    C-\u003e\u003eH: Tool call (e.g. git push)\n    H-\u003e\u003eT: 💻 Bash: git push\n    T-\u003e\u003eU: [✅ Allow] [❌ Deny]\n    U-\u003e\u003eT: Tap Allow\n    H--\u003e\u003eC: allow\n\n    C-\u003e\u003eH: AskUserQuestion\n    H-\u003e\u003eT: ❓ Which approach?\n    T-\u003e\u003eU: [Option A] [Option B]\n    U-\u003e\u003eT: Tap Option A\n    H--\u003e\u003eC: deny + context: \"User chose A\"\n\n    C-\u003e\u003eH: Stop (finished)\n    H-\u003e\u003eT: 🤖 Claude stopped: \"Done. What's next?\"\n    U-\u003e\u003eT: \"Now write tests for it\"\n    H--\u003e\u003eC: block + reason: \"Now write tests\"\n```\n\n### Contents\n\n- [Features](#features) · [Demo](#demo) · [Quick Start](#quick-start) · [Usage](#usage)\n- [How It Works](#how-it-works) · [Configuration](#configuration) · [Security](#security) · [Troubleshooting](#troubleshooting)\n\n---\n\n## Features\n\n- **Three modes** — `cctg on` (full remote), `cctg tools-only` (approvals only), `cctg off`\n- **Remote continuation** — when Claude stops, send your next instruction from Telegram\n- **Question interception** — AskUserQuestion prompts forwarded to Telegram with option buttons\n- **Permission-aware** — reads your `~/.claude/settings.json` allow list; only prompts for tools that would normally require approval\n- **Fail-closed** — timeout, crash, or network error = denied (tool calls) or pass-through (stop hook)\n- **Anti-replay** — each request has a unique ID; stale button presses are ignored\n- **Zero dependencies** — pure Node.js, no external packages\n- **No daemon** — each hook invocation is a fresh process; no background services\n\n---\n\n## Demo\n\n**Tool approval** — when Claude tries to run an unapproved tool:\n\n```\n💻 Bash\n────────────────────\ngit push origin main\n\n[✅ Allow]  [❌ Deny]\n```\n\n**Question answering** — when Claude asks a clarifying question:\n\n```\n❓ Claude is asking\n────────────────────\nWhich approach do you prefer?\n\n  1. Option A — Simple and fast\n  2. Option B — More thorough\n\n[Option A]  [Option B]\n```\n\n**Remote continuation** — when Claude finishes and is waiting:\n\n```\n🤖 Claude stopped\n────────────────────\nDone! I've refactored the auth module\nand updated the tests.\n\nReply to continue · /done to stop\n```\n\nReply with your next instruction, or `/done` to let Claude stop.\n\n---\n\n## Prerequisites\n\n- **Node.js 18+** (Claude Code already requires this)\n- **Telegram account** with a bot (free, takes 2 minutes)\n\n---\n\n## Quick Start\n\n### 1. Install\n\n```bash\nnpm install -g cctg\n```\n\nOr clone and build from source:\n\n```bash\ngit clone https://github.com/laveez/cctg.git\ncd cctg \u0026\u0026 npm install \u0026\u0026 npm run build\n```\n\n### 2. Create a Telegram bot\n\n1. Open [@BotFather](https://t.me/BotFather) on Telegram\n2. Send `/newbot` and follow the prompts\n3. Copy the bot token\n\n### 3. Get your chat ID\n\n1. Open [@userinfobot](https://t.me/userinfobot) on Telegram\n2. Send any message — it replies with your user ID\n\n### 4. Run setup\n\n```bash\ncctg init\n```\n\nEnter your bot token and chat ID. The wizard writes `~/.cctg.json` and registers the hook in `~/.claude/settings.json`.\n\n---\n\n## Usage\n\n### Modes\n\n```bash\ncctg on          # Full remote — tools, questions, and continuation via Telegram\ncctg tools-only  # Tool approvals only — questions and input at terminal\ncctg off         # Disabled — normal CLI prompts\ncctg status      # Show current mode\n```\n\n### AFK workflow\n\n```bash\ncctg on\nclaude \"refactor the auth module\"\n# Approve tools, answer questions, send follow-ups — all from your phone\n\n# Back at keyboard\ncctg tools-only  # or: cctg off\n# Terminal input again. If Claude was waiting, it resumes.\n```\n\n### Permission-aware filtering\n\ncctg reads your `~/.claude/settings.json` permission rules. Tools already in your `permissions.allow` list pass through silently — only unlisted tools trigger Telegram prompts.\n\nThis means you won't get spammed with messages for every `Read`, `Glob`, or `git status` call.\n\n---\n\n## How it works\n\ncctg registers two [Claude Code hooks](https://code.claude.com/docs/en/hooks):\n\n- **PreToolUse** — intercepts tool calls and AskUserQuestion prompts\n- **Stop** — intercepts when Claude finishes, enabling remote continuation\n\n```mermaid\nflowchart TD\n    A[Tool call] --\u003e B{Mode?}\n    B -- off --\u003e C[Pass through]\n    B -- on / tools-only --\u003e D{Already permitted?}\n    D -- Yes --\u003e C\n    D -- No --\u003e E{AskUserQuestion\u003cbr/\u003e+ mode = on?}\n    E -- Yes --\u003e F[Send question\u003cbr/\u003eto Telegram]\n    F --\u003e G[User picks option]\n    G --\u003e H[Deny + inject answer\u003cbr/\u003eas context]\n    E -- No --\u003e I[Send to Telegram\u003cbr/\u003eAllow / Deny buttons]\n    I --\u003e J{User taps}\n    J -- Allow --\u003e K[Allow]\n    J -- Deny/Timeout --\u003e L[Deny]\n\n    M[Claude stops] --\u003e N{Mode = on?}\n    N -- No --\u003e O[Pass through]\n    N -- Yes --\u003e P[Send last message\u003cbr/\u003eto Telegram]\n    P --\u003e Q{User response}\n    Q -- Text reply --\u003e R[Block stop +\u003cbr/\u003econtinue with instruction]\n    Q -- /done --\u003e O\n    Q -- Timeout --\u003e O\n    Q -- Mode changed --\u003e O\n\n    style C fill:#2d4a2d\n    style K fill:#2d4a2d\n    style H fill:#2d4a2d\n    style R fill:#2d4a2d\n    style L fill:#4a2d2d\n    style O fill:#2d4a2d\n```\n\nNo daemon. No background process. Each hook invocation is a fresh Node.js process that exits after the decision.\n\n---\n\n## Configuration\n\nConfig lives at `~/.cctg.json` (created by `cctg init`):\n\n```json\n{\n  \"botToken\": \"123456:ABC-DEF...\",\n  \"chatId\": \"987654321\",\n  \"timeoutSeconds\": 300,\n  \"remoteTimeoutSeconds\": 300,\n  \"autoApprove\": [],\n  \"autoDeny\": []\n}\n```\n\n| Field | Description | Default |\n|---|---|---|\n| `botToken` | Telegram bot token from @BotFather | required |\n| `chatId` | Your Telegram user ID | required |\n| `timeoutSeconds` | Seconds to wait for tool approval before auto-denying | `300` |\n| `remoteTimeoutSeconds` | Seconds to wait for continuation input (Stop hook) | `timeoutSeconds` |\n| `autoApprove` | Tool names to silently allow (bypasses Telegram) | `[]` |\n| `autoDeny` | Tool names to silently deny | `[]` |\n\n\u003e **Note:** `autoApprove` / `autoDeny` in `~/.cctg.json` are for tools you want cctg to handle directly — separate from the `permissions.allow` list in `~/.claude/settings.json`, which cctg respects automatically.\n\n---\n\n## Security\n\n- **Fail-closed** — if anything goes wrong (timeout, network error, crash), the tool call is denied\n- **Chat ID verification** — only responses from your configured Telegram user ID are accepted\n- **Request ID matching** — each permission request has a unique ID, preventing stale button presses from being accepted\n- **No secrets in code** — bot token and chat ID live in `~/.cctg.json`, gitignored\n- **Polling mode** — no webhook server, no public URL, no inbound connections\n\n---\n\n## Troubleshooting\n\n**Bot not responding to button taps**\n\n- Ensure you sent `/start` to your bot in Telegram before using it\n- Verify your chat ID matches: send a message to [@userinfobot](https://t.me/userinfobot)\n- Check that `~/.cctg.json` has the correct `botToken` and `chatId`\n\n**Tool calls not going to Telegram**\n\n- Run `cctg status` to verify cctg is on\n- Check that the tool isn't already in your `~/.claude/settings.json` `permissions.allow` list (those pass through by design)\n\n**Timeout / auto-deny too fast**\n\n- Increase `timeoutSeconds` in `~/.cctg.json` (default is 300 = 5 minutes)\n- For the Stop hook, set `remoteTimeoutSeconds` separately if needed\n- The hook timeout in `~/.claude/settings.json` should be higher than your timeout values (set automatically by `cctg init`)\n\n**Terminal frozen (remote mode)**\n\n- This is expected when `cctg on` — the Stop hook is waiting for your Telegram response\n- To take back control: open another terminal and run `cctg tools-only` or `cctg off`\n- The Stop hook detects the mode change and releases the terminal\n\n---\n\n## See Also\n\n- **[ccsl](https://github.com/laveez/ccsl)** — Claude Code Statusline. A rich, information-dense statusline for Claude Code. When cctg is installed, ccsl shows the current cctg mode (`📱 ON` / `📱 off`) as a badge in your statusline.\n\n---\n\n## Contributing\n\nContributions are welcome! This is a small project — open an issue or submit a PR.\n\n```bash\ngit clone https://github.com/laveez/cctg.git\ncd cctg\nnpm install\nnpm run dev    # Watch mode — rebuilds on change\n```\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flaveez%2Fcctg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flaveez%2Fcctg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flaveez%2Fcctg/lists"}