{"id":50778046,"url":"https://github.com/nkschmidt/agentgram","last_synced_at":"2026-06-12T01:04:01.911Z","repository":{"id":361026048,"uuid":"1252775026","full_name":"nkschmidt/agentgram","owner":"nkschmidt","description":"Telegram bot that proxies chat messages to CLI coding agents (Claude Code, opencode) with streaming responses, voice input, and per-user sessions.","archived":false,"fork":false,"pushed_at":"2026-05-28T22:32:40.000Z","size":83,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-05-28T23:20:23.116Z","etag":null,"topics":["ai-agent","ai-agents","claude","claude-code","opencode","telegram","telegrambot"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nkschmidt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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-05-28T21:25:23.000Z","updated_at":"2026-05-28T22:32:44.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/nkschmidt/agentgram","commit_stats":null,"previous_names":["nkschmidt/agentgram"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/nkschmidt/agentgram","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nkschmidt%2Fagentgram","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nkschmidt%2Fagentgram/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nkschmidt%2Fagentgram/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nkschmidt%2Fagentgram/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nkschmidt","download_url":"https://codeload.github.com/nkschmidt/agentgram/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nkschmidt%2Fagentgram/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34224103,"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-11T02:00:06.485Z","response_time":57,"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-agents","claude","claude-code","opencode","telegram","telegrambot"],"created_at":"2026-06-12T01:04:01.162Z","updated_at":"2026-06-12T01:04:01.906Z","avatar_url":"https://github.com/nkschmidt.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# agentgram — Telegram bot wrapper for CLI agents\n\n[![Go](https://img.shields.io/badge/Go-1.25+-00ADD8?style=flat-square\u0026logo=go)](https://go.dev/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow?style=flat-square)](LICENSE)\n\nA Telegram bot that hooks [Claude Code](https://claude.ai/code) and [OpenCode](https://github.com/opencode-ai/opencode) into Telegram — chat with AI agents straight from your messenger and drive your projects from any device.\n\n## What is it?\n\nThe bot turns Telegram into a console for CLI agents. Send messages, get streamed responses, just like working in a terminal:\n\n```\nYou: Refactor the auth middleware, extract it into a separate package\nBot: ⏳ Working...\n      📖 Read: middleware.go\n      📖 Read: auth.go\n      ✏️ Edit: middleware.go\nBot: Done. Moved authentication into package auth, updated imports, all 12 tests pass.\n```\n\n## Features\n\n### AI backends\n\n- **Claude Code** — per-message CLI invocation with `--resume` for multi-turn sessions. Supports thinking, tool_use, result.\n- **OpenCode** — HTTP API to a local `opencode serve` with SSE streaming and lazy server startup.\n- **Modular architecture** — adding a new backend = one package implementing the `Backend` interface.\n\n### In-chat streaming\n\n- A single message updates as chunks arrive (typing + edit).\n- An `⏹ Stop` button — soft interrupt (SIGINT / `/abort`).\n- The final answer is formatted as HTML with a plain-text fallback.\n\n### Attachments\n\n- **Documents and photos** — downloaded to the server, the path is passed to the agent.\n- **Voice messages** — transcribed via whisper.cpp right inside the bot.\n\n### Agent ↔ user channel (MCP)\n\nThe bot runs a local [MCP](https://modelcontextprotocol.io/) server that gives agents three extra tools, so they can reach **back** to your chat — not just reply with text:\n\n- **`send_photo`** — send an image inline as a photo (with optional caption).\n- **`send_document`** — send any file as a downloadable attachment.\n- **`ask_user`** — ask a question mid-task; options are shown as tappable buttons, and you can also just reply with text.\n\n```\nYou: Plot the sales data from report.csv and send me the chart\nBot: 📊 Built the chart from 1,240 rows.\n     [photo: sales_q3.png]      ← delivered via send_photo\n\nYou: Deploy the new version\nBot: ❓ Which environment?\n     [ Staging ] [ Production ]  ← ask_user buttons (or type your own answer)\n```\n\nRouting is per-user: the bot mints a Bearer token per user and wires it into each backend's MCP config, so a tool call always lands in the right chat. `ask_user` blocks until you answer (button tap or typed reply); `/new_session` and `/restart` always work as an escape hatch. Works for both backends:\n\n- **Claude Code** — token passed per invocation via `--mcp-config` + `--allowedTools`; the agent is nudged toward these tools via `--append-system-prompt`.\n- **OpenCode** — registered as a remote MCP server in a per-workdir `opencode.json` (the bot writes/merges it on session start); nudged via the per-message `system` instruction.\n\n### Settings\n\n- **Working directories** — per-user, folder browser via inline keyboard, up to 100 subdirectories per screen.\n- **Whitelist** — access by `user_id`; the first writer is added automatically.\n- **Voice** — paths to whisper-cli and the model are configured via `/settings`, with autodetect on startup.\n\n### Commands\n\n| Command | Description |\n|---------|-------------|\n| `/settings` | Allowed users, working directory, voice |\n| `/new_session` | New session with backend selection |\n| `/restart` | Restart the bot (in-place exec) |\n\n## Quick start\n\n### Requirements\n\n- **Go 1.25+**\n- **Telegram Bot Token** — get one from [@BotFather](https://t.me/botfather)\n- **Claude Code CLI** — [install](https://claude.ai/code) (for the claude backend)\n- **OpenCode** — [install](https://github.com/opencode-ai/opencode) (for the opencode backend)\n- **whisper.cpp** — optional, for voice transcription\n\n### Install\n\n```bash\ngit clone https://github.com/nkschmidt/agentgram.git\ncd agentgram\n```\n\n### Configure\n\n```bash\ncp .env.example .env\n# Edit .env:\n```\n\n```env\nTELEGRAM_BOT_TOKEN=\u003cTOKEN\u003e\n```\n\nOn first run the bot will automatically:\n1. Detect paths to `whisper-cli` and the model (if present on the system).\n2. Save them to `settings.json`.\n3. Add the first user to the whitelist.\n\n### Run\n\n```bash\ngo run ./cmd/bot\n```\n\nWrite to the bot on Telegram — the first user is added to the whitelist automatically.\n\n## Project structure\n\n```\ncmd/bot/main.go              — entry point\ninternal/settings            — runtime settings (JSON, RWMutex)\ninternal/router              — routing: Message → command / state / backend\ninternal/backend             — Backend interface + factory registry\n  claude                     — per-message CLI with --resume\n  opencode                   — HTTP API + SSE, lazy server\n  toolfmt                    — tool-call rendering\ninternal/session             — per-user sessions, auto-stop, chunk handler\ninternal/command             — commands, streaming, callbacks, state machine\ninternal/bot                 — tgbotapi glue: service, replier, composer, sender\ninternal/mcp                 — local MCP server: send_photo / send_document\ninternal/asr                 — transcription (whisper.cpp + noop)\n```\n\n## Architecture\n\n### Backend abstraction\n\nEvery AI backend implements a single interface:\n\n```go\ntype Backend interface {\n    Start(ctx context.Context) error\n    Send(input string) error\n    Recv() \u003c-chan Chunk\n    Interrupt() error\n    Stop() error\n}\n```\n\nFactories are registered in a global registry by name (`claude`, `opencode`). A new backend = a new package without touching the core.\n\n### Sessions\n\n`session.Manager` keeps one active session per user. When a new message is sent the previous session is stopped automatically. Chunks are delivered to the chat via `StreamCoordinator`.\n\n### Settings\n\nStored in `settings.json` (bot cwd). Keys:\n\n```json\n{\n  \"allowed_users\": [150041509],\n  \"work_dirs\": {\n    \"150041509\": \"/path/to/project\"\n  },\n  \"whisper_bin\": \"/opt/homebrew/bin/whisper-cli\",\n  \"whisper_model\": \"/path/to/ggml-base.bin\"\n}\n```\n\n- `allowed_users` — empty list = autoseed (the first user is added).\n- `work_dirs` — when the directory changes, the user's session is restarted.\n- `whisper_*` — autodetected on startup, changed via `/settings`.\n\n## Deployment\n\n### Local\n\n```bash\ngo build -o bot ./cmd/bot\n./bot\n```\n\n### VPS (systemd)\n\n```bash\nsudo tee /etc/systemd/system/agentgram.service \u003e /dev/null \u003c\u003cEOF\n[Unit]\nDescription=agentgram — Telegram AI Agent Bot\nAfter=network.target\n\n[Service]\nType=simple\nWorkingDirectory=/opt/agentgram\nExecStart=/opt/agentgram/bot\nRestart=on-failure\nRestartSec=5\nEnvironmentFile=/opt/agentgram/.env\n\n[Install]\nWantedBy=multi-user.target\nEOF\n\nsudo systemctl enable --now agentgram\n```\n\n## Extending\n\n### New backend\n\n1. Create a package `internal/backend/X`.\n2. Implement `Backend` + `Factory`.\n3. Register it in `backendReg` in `main.go`.\n\n### New command\n\n1. Create a file in `internal/command/` with a `Command` implementation.\n2. Register it in `registry` in `main.go`.\n\n### New /settings section\n\n1. Implement `SettingsSection` (Slug + MenuButton + Handle + Accept + ResetState).\n2. Add it as `section_*.go` and register in `command.NewSettings(...)`.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnkschmidt%2Fagentgram","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnkschmidt%2Fagentgram","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnkschmidt%2Fagentgram/lists"}