{"id":50900454,"url":"https://github.com/hah23255/kimi-to-im","last_synced_at":"2026-06-16T02:03:53.635Z","repository":{"id":354867944,"uuid":"1221182336","full_name":"hah23255/kimi-to-im","owner":"hah23255","description":"Telegram bridge for the Kimi CLI — chat with Moonshot Kimi from your phone, sessions persist, single-user, ~1.7K LOC Python, systemd-supervised, MIT.","archived":false,"fork":false,"pushed_at":"2026-04-30T15:17:01.000Z","size":97,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-30T16:23:29.814Z","etag":null,"topics":["ai-agent","ai-cli","asyncio","chatbot","cli-tool","daemon","gpg-signed","homelab","kimi-cli","kimi-k2","llm","moonshot-ai","python","self-hosted","single-user","systemd","telegram-api","telegram-bot","telegram-bridge","terminal-ai"],"latest_commit_sha":null,"homepage":"https://github.com/hah23255/kimi-to-im","language":"Python","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/hah23255.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","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-04-25T21:27:53.000Z","updated_at":"2026-04-30T15:26:50.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/hah23255/kimi-to-im","commit_stats":null,"previous_names":["hah23255/kimi-to-im"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/hah23255/kimi-to-im","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hah23255%2Fkimi-to-im","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hah23255%2Fkimi-to-im/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hah23255%2Fkimi-to-im/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hah23255%2Fkimi-to-im/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hah23255","download_url":"https://codeload.github.com/hah23255/kimi-to-im/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hah23255%2Fkimi-to-im/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34387478,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-16T02:00:06.860Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["ai-agent","ai-cli","asyncio","chatbot","cli-tool","daemon","gpg-signed","homelab","kimi-cli","kimi-k2","llm","moonshot-ai","python","self-hosted","single-user","systemd","telegram-api","telegram-bot","telegram-bridge","terminal-ai"],"created_at":"2026-06-16T02:03:52.758Z","updated_at":"2026-06-16T02:03:53.626Z","avatar_url":"https://github.com/hah23255.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# 📱 kimi-to-im\n\n### Chat with [Kimi CLI](https://github.com/MoonshotAI/kimi-cli) from Telegram\n\n**Self-hosted · single-user · ~1.7K LOC Python · systemd-supervised**\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=for-the-badge)](LICENSE)\n[![Python 3.11+](https://img.shields.io/badge/Python-3.11+-3776AB?style=for-the-badge\u0026logo=python\u0026logoColor=white)](https://www.python.org/downloads/)\n[![systemd](https://img.shields.io/badge/systemd-user_unit-FCC624?style=for-the-badge\u0026logo=linux\u0026logoColor=black)](https://www.freedesktop.org/wiki/Software/systemd/)\n[![Telegram](https://img.shields.io/badge/Telegram-26A5E4?style=for-the-badge\u0026logo=telegram\u0026logoColor=white)](https://telegram.org/)\n[![Kimi](https://img.shields.io/badge/Kimi-K2.6-FF6B35?style=for-the-badge)](https://github.com/MoonshotAI/kimi-cli)\n\n[![CI](https://github.com/hah23255/kimi-to-im/actions/workflows/test.yml/badge.svg)](https://github.com/hah23255/kimi-to-im/actions/workflows/test.yml)\n[![GitHub stars](https://img.shields.io/github/stars/hah23255/kimi-to-im?style=social)](https://github.com/hah23255/kimi-to-im/stargazers)\n[![GitHub forks](https://img.shields.io/github/forks/hah23255/kimi-to-im?style=social)](https://github.com/hah23255/kimi-to-im/network/members)\n\n\u003c/div\u003e\n\n---\n\n## 💡 Why this exists\n\nYou already use Kimi CLI at your desk. This bridge lets you keep the **same conversation** going from your phone — over Telegram — without changing how Kimi runs locally. You send a message, the bridge spawns `kimi` on your machine, and the reply lands back in Telegram. Sessions persist per chat, so follow-ups pick up where you left off.\n\n**Single-user, single-host, text-only by design.** No cloud component. No account system. The bot replies only to user IDs you explicitly whitelist.\n\n---\n\n## 🏗️ Architecture\n\n```mermaid\nflowchart LR\n    User([📱 You\u003cbr/\u003eon Telegram])\n    TG[Telegram\u003cbr/\u003eBot API]\n    Bridge[bridge daemon\u003cbr/\u003e~1.7K LOC Python\u003cbr/\u003esystemd --user]\n    Kimi[kimi CLI\u003cbr/\u003esubprocess\u003cbr/\u003eper turn]\n    State[(state.json\u003cbr/\u003echat → session)]\n    OAuth[~/.kimi/\u003cbr/\u003ecredentials]\n\n    User --\u003e|message| TG\n    TG --\u003e|long-poll\u003cbr/\u003egetUpdates| Bridge\n    Bridge --\u003e|spawn\u003cbr/\u003e--print -S sid| Kimi\n    Kimi --\u003e|reasoning_content\u003cbr/\u003e+ output| Bridge\n    Bridge --\u003e|sendMessage| TG\n    TG --\u003e|reply| User\n    Bridge \u003c--\u003e|read/write| State\n    Kimi \u003c--\u003e|JWT auto-refresh| OAuth\n\n    style User fill:#26A5E4,color:#fff,stroke:#1a8cc4\n    style TG fill:#26A5E4,color:#fff,stroke:#1a8cc4\n    style Bridge fill:#FF6B35,color:#fff,stroke:#cc5028\n    style Kimi fill:#9B59B6,color:#fff,stroke:#7d3f95\n    style State fill:#34495E,color:#fff,stroke:#222\n    style OAuth fill:#34495E,color:#fff,stroke:#222\n```\n\n---\n\n## 🔁 Turn-by-turn flow\n\n```mermaid\nsequenceDiagram\n    autonumber\n    participant U as 📱 User\u003cbr/\u003e(Telegram)\n    participant T as Telegram\u003cbr/\u003eAPI\n    participant D as bridge\u003cbr/\u003edaemon\n    participant K as kimi\u003cbr/\u003eCLI\n    participant S as state.json\n\n    U-\u003e\u003eT: \"Continue the analysis…\"\n    T--\u003e\u003eD: getUpdates → message\n    D-\u003e\u003eD: is_authorized(user_id) ?\n    D-\u003e\u003eS: lookup session_id by chat_id\n    S--\u003e\u003eD: sid = abc123…\n    D-\u003e\u003eT: sendChatAction(\"typing\")\n    par heartbeat (every 4s)\n        D-\u003e\u003eT: typing\n    and progress notice (250s, 600s)\n        D--\u003e\u003eU: \"🤔 Still thinking…\"\n    and kimi subprocess\n        D-\u003e\u003eK: kimi --print -S abc123\n        K--\u003e\u003eK: K2.6 reasoning + tool calls\n        K--\u003e\u003eD: reply text\n    end\n    D-\u003e\u003eT: sendMessage(reply)\n    T--\u003e\u003eU: 💬 Kimi's answer\n    D-\u003e\u003eS: persist (no change, sid sticks)\n```\n\n---\n\n## ⚡ Quickstart (5 minutes)\n\n```mermaid\nflowchart TD\n    A[1\\. Get bot token\u003cbr/\u003efrom @BotFather] --\u003e B[2\\. Get your\u003cbr/\u003eTelegram user ID\u003cbr/\u003efrom @userinfobot]\n    B --\u003e C[3\\. git clone +\u003cbr/\u003einstall.sh]\n    C --\u003e D[4\\. Edit config.json\u003cbr/\u003etoken + allowlist]\n    D --\u003e E[5\\. systemctl --user\u003cbr/\u003estart the unit]\n    E --\u003e F[✅ Send hello\u003cbr/\u003eto your bot]\n\n    style A fill:#26A5E4,color:#fff\n    style B fill:#26A5E4,color:#fff\n    style C fill:#9B59B6,color:#fff\n    style D fill:#9B59B6,color:#fff\n    style E fill:#27AE60,color:#fff\n    style F fill:#27AE60,color:#fff\n```\n\nYou need: **Linux** with `systemd --user`, **Python 3.11+**, [`uv`](https://docs.astral.sh/uv/), and a working `kimi` CLI on your `PATH`. Full prerequisites and verification commands live in [`docs/deployment.md`](docs/deployment.md).\n\n**1. Get a Telegram bot token.** Message [@BotFather](https://t.me/BotFather), send `/newbot`, follow the prompts. Copy the token.\n\n**2. Get your Telegram user ID.** Message [@userinfobot](https://t.me/userinfobot). It replies with your numeric ID.\n\n**3. Install.**\n\n```sh\ngit clone https://github.com/hah23255/kimi-to-im.git ~/.kimi/plugins/telegram-bridge\ncd ~/.kimi/plugins/telegram-bridge\nbash install.sh\n```\n\n\u003e Expected: a `.venv/` is created and a systemd user unit registered.\n\n**4. Configure.**\n\n```sh\ncp config.example.json config.json\nchmod 600 config.json\n$EDITOR config.json   # paste bot_token, add your Telegram user ID to allowed_user_ids\n```\n\n**5. Start.**\n\n```sh\nsystemctl --user start kimi-telegram-bridge.service\n```\n\n\u003e Expected: `systemctl --user is-active kimi-telegram-bridge.service` prints `active`. Send \"hello\" to your bot from Telegram — within ~10s the typing indicator appears, then a Kimi reply.\n\nFor a more detailed walk-through with pre-flight checks and smoke tests, see [`docs/deployment.md`](docs/deployment.md).\n\n---\n\n## ⏱️ Timing \u0026 timeouts\n\n```mermaid\ngantt\n    title Bridge timing budgets per Telegram turn\n    dateFormat ss\n    axisFormat %Ss\n\n    section Typing indicator\n    Refresh every 4s         :active, 0, 4s\n    Refresh                  :active, 4, 4s\n    Refresh                  :active, 8, 4s\n\n    section Progress notices\n    \"Still thinking…\" @ 250s :crit, 250, 5s\n    \"Still thinking…\" @ 600s :crit, 600, 5s\n\n    section Kimi subprocess\n    Allowed work window      :active, 0, 900s\n    Hard kill                :crit, 900, 5s\n\n    section JWT\n    OAuth token (15min TTL)  :active, 0, 900s\n    Auto-refresh             :crit, 600, 1s\n```\n\n| Event | Time |\n|---|---|\n| Typing indicator refresh | every 4 s |\n| First progress notice | 250 s (~4 min) |\n| Second progress notice | 600 s (~10 min) |\n| Kimi subprocess hard timeout | **900 s** (15 min, aligned with JWT TTL) |\n| OAuth JWT auto-refresh cadence | every 10 min (TTL is 15 min) |\n\n\u003e The 15-minute ceiling is intentional — Kimi K2.6 with thinking on a 160 K-token context routinely needs 5–12 minutes per complex turn. We bound long enough for real work, short enough that truly hung subprocesses get cleaned up.\n\n---\n\n## 🛡️ Defence-in-depth\n\n```mermaid\ngraph TD\n    Inbound[Inbound\u003cbr/\u003eTelegram message]\n    Allowlist{user_id in\u003cbr/\u003eallowed_user_ids?}\n    ChatlistCheck{chat_id in\u003cbr/\u003eallowed_chat_ids?}\n    SessionCheck{session_id matches\u003cbr/\u003euuid4 hex?}\n    Kimi[Spawn kimi]\n    Drop[Dropped silently\u003cbr/\u003e+ logged]\n\n    Inbound --\u003e Allowlist\n    Allowlist --\u003e|no| Drop\n    Allowlist --\u003e|yes| ChatlistCheck\n    ChatlistCheck --\u003e|no| Drop\n    ChatlistCheck --\u003e|yes| SessionCheck\n    SessionCheck --\u003e|no| Drop\n    SessionCheck --\u003e|yes| Kimi\n\n    style Drop fill:#E74C3C,color:#fff\n    style Kimi fill:#27AE60,color:#fff\n```\n\nThe systemd unit ships hardened by default:\n\n| Layer | Mechanism |\n|---|---|\n| **Identity** | Default-deny allowlist on `allowed_user_ids` + `allowed_chat_ids` |\n| **Subprocess argv** | `session_id` validated against uuid4-hex regex before being passed to `kimi` |\n| **Network** | `RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6` |\n| **Filesystem** | `PrivateTmp`, `UMask=0077`, config 0600 |\n| **Kernel surface** | `ProtectKernelTunables`, `ProtectKernelModules`, `LockPersonality` |\n| **Syscalls** | `SystemCallFilter=@system-service ~@privileged ~@resources` |\n| **Logs** | `httpx` INFO suppressed so bot token never lands in `bridge.log` |\n| **Liveness** | `Restart=on-failure`, exit-124 timeout safety net |\n\nFull security policy: [`SECURITY.md`](SECURITY.md). Audit findings: [`docs/security-scan.md`](docs/security-scan.md).\n\n---\n\n## 📊 Repo at a glance\n\n| | |\n|---|---|\n| **Language** | Python 3.11+ |\n| **Source LOC** | 1,698 |\n| **Test files** | 10 (full suite \u003c 2 s) |\n| **External runtime deps** | 1 (`httpx`) |\n| **External system deps** | `kimi` CLI on `PATH`, systemd-user |\n| **Lines per turn (avg request path)** | ~50 |\n| **First-launch RAM** | ~22 MB (idle) |\n| **Steady-state RAM** | ~80–200 MB depending on Telegram polling state |\n\n```mermaid\npie title Source code distribution\n    \"src/ daemon code\" : 720\n    \"tests/\" : 880\n    \"config + plugin glue\" : 98\n```\n\n---\n\n## 🧰 What it does and doesn't\n\nThis is intentionally a small, opinionated tool.\n\n**It does:**\n\n- ✅ Bridge Telegram ↔ Kimi CLI as separate subprocesses per turn\n- ✅ Persist session continuity per chat\n- ✅ Run as a `systemctl --user` service with hardening\n- ✅ Refresh the OAuth JWT automatically (10-min cadence, 15-min TTL)\n- ✅ Stream typing indicator + progress notices for long turns\n- ✅ Surface friendly error messages (no raw stderr leaks)\n- ✅ Validate inputs against a default-deny allowlist\n\n**It does NOT:**\n\n- ❌ Support Discord, Slack, Feishu, QQ, or any IM other than Telegram\n- ❌ Handle images, voice, or file uploads (text only)\n- ❌ Stream replies token-by-token (Kimi emits per-turn JSON, bridge sends per-turn)\n- ❌ Expose Kimi's internal tool calls or ask for permission before they run\n- ❌ Sync state between machines (one bridge per host)\n- ❌ Multi-user (architecturally single-user — by design, not laziness)\n\nIf you need any of these, this bridge is the wrong tool.\n\n---\n\n## ⚙️ Configuration\n\nThe full reference lives in [`docs/operations.md`](docs/operations.md#configure-the-bridge). The minimum to know:\n\n| Field | Required | Purpose |\n|---|---|---|\n| `telegram.bot_token` | yes | The string from BotFather. |\n| `telegram.allowed_user_ids` | yes | Whitelist of Telegram user IDs. Empty = nobody can talk to the bot (default-deny). |\n| `telegram.allowed_chat_ids` | recommended | Optional chat-level whitelist. Set to your DM's chat id (= your user id) so the bot won't respond inside groups. |\n| `kimi.default_workdir` | no | Where Kimi runs. Defaults to Kimi's own default. |\n| `kimi.model` | no | Empty = Kimi's default model. |\n\n`config.json` is gitignored. Don't commit your token.\n\n---\n\n## 📚 Documentation\n\n| Document | Read this when... |\n|---|---|\n| [`docs/deployment.md`](docs/deployment.md) | You're installing for the first time. |\n| [`docs/operations.md`](docs/operations.md) | You're running the bridge day-to-day, or troubleshooting. |\n| [`docs/design.md`](docs/design.md) | You want to understand why the architecture looks the way it does. |\n| [`docs/security-scan.md`](docs/security-scan.md) | You want the formal pre-publication audit findings. |\n| [`SECURITY.md`](SECURITY.md) | You found a vulnerability or want the security policy. |\n| [`CONTRIBUTING.md`](CONTRIBUTING.md) | You want to send a patch. |\n\n---\n\n## 🤝 Contributing\n\nPRs welcome. Please read [`CONTRIBUTING.md`](CONTRIBUTING.md) and run the tests:\n\n```sh\nuv venv .venv --python 3.11\nuv pip install -e \".[dev]\"\n.venv/bin/pytest -v\n```\n\nThe full suite runs in **under 2 seconds** and is the gate for CI.\n\n---\n\n## 📜 License\n\nMIT — see [LICENSE](LICENSE).\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n**Built for one user, one host, one Telegram chat.**\n**Not trying to be more than that.**\n\n[Report an issue](https://github.com/hah23255/kimi-to-im/issues) · [Security policy](SECURITY.md) · [Discussions](https://github.com/hah23255/kimi-to-im/discussions)\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhah23255%2Fkimi-to-im","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhah23255%2Fkimi-to-im","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhah23255%2Fkimi-to-im/lists"}