{"slug": "hasharot-control-a-claude-code-agent-on-your-machine-from-telegram", "title": "Hasharot – Control a Claude Code agent on your machine from Telegram", "summary": "Hasharot, an open-source tool that connects Telegram to a Claude Code agent running locally on a user's machine, has been released. It allows users to control the agent via Telegram messages, enabling file operations, code editing, web browsing, and voice interactions while keeping code and secrets on the local machine. The tool supports team workflows with per-user sandboxing and owner approvals.", "body_md": "**Your and your teammates' personal AI agent, running on your machine, controlled from Telegram.**\n\n```\n  Telegram  ──▶  Grammy Bot  ──▶  Claude Agent SDK  ──▶  Your Machine\n  voice/text     command router     agentic runtime       bash, files, code\n```\n\n[Features](#features) · [Quick Start](#quick-start) · [Commands](#commands) · [Team Workflow](#team-workflow--topics) · [Configuration](#configuration-reference) · [Architecture](#architecture) · [Context & Memory](#context--memory) · [Roadmap](#roadmap)\n\nHasharot bridges Telegram to a **full Claude Code agent** running locally on your machine. Send a message in Telegram — Claude reads your files, runs commands, writes code, browses Reddit, fetches Medium articles, transcribes voice notes, and speaks responses back. All from your phone.\n\nThis is not a simple API wrapper. It's the real Claude Code agent with tool access — Bash, file I/O, code editing, web browsing — packaged behind a Telegram interface with streaming responses, session memory, rich output formatting, and a multi-user access-control layer.\n\n**Why it's different:**\n\n- 🧠\n**The real agent, not a chat wrapper**— Bash, file I/O, code editing, and web access, driven by the Claude Agent SDK - 📱\n**Your machine, your phone**— code and secrets never leave your computer; you just drive it from Telegram - 👥\n**Team-ready**— per-user sandboxing, owner approvals, and one parallel session per forum topic - 🎙\n**Voice in, voice out**— talk to your codebase and hear it answer back - 🔌\n**Delegate & forget**— hand a task to an autonomous[Paperclip](https://github.com/paperclipai/paperclip)agent and get the finished result (with docs, links, and follow-up questions) pushed back to Telegram\n\n⭐\n\nIf Hasharot looks useful, star the repo— it helps others find it and it genuinely makes our day.\n\n|\n|\n\nAlready using a coding agent (Claude Code, Cursor, Codex, …)? Just paste this one line into it — the agent does the whole setup and only asks you for a bot token and your Telegram ID:\n\n```\nFetch https://raw.githubusercontent.com/Mamasodikov/hasharot/main/docs/AGENT_SETUP.md and follow it to set up Hasharot on this machine.\n```\n\nPrefer doing it by hand? Continue below.\n\n| Requirement | Notes |\n|---|---|\nNode.js 22+ |\nwith npm |\nClaude Code CLI |\ninstalled and authenticated — `claude` in your PATH |\nTelegram bot token |\nfrom\n|\n\n**Your Telegram user ID**[@userinfobot](https://t.me/userinfobot)\n\n```\ngit clone https://github.com/Mamasodikov/hasharot.git\ncd hasharot\ncp .env.example .env\n```\n\nEdit `.env`\n\n:\n\n```\nTELEGRAM_BOT_TOKEN=your_bot_token\nALLOWED_USER_IDS=your_user_id\nOWNER_USER_ID=your_user_id     # you = admin (approvals, /access, /answer_policy)\nnpm install\nnpm run dev        # dev mode with hot reload\n```\n\nOpen your bot in Telegram → `/start`\n\n| Command | Description |\n|---|---|\n`/start` |\nWelcome message |\n`/project` |\nSet working directory (interactive picker) |\n`/newproject <name>` |\nCreate and switch to a new project |\n`/default [off]` |\nShow or clear this chat's default project |\n`/clear` |\nClear conversation + session |\n`/status` |\nCurrent session info |\n`/sessions` |\nList saved sessions |\n`/resume` |\nPick from recent sessions |\n`/continue` |\nResume most recent session |\n`/teleport` |\nMove session to terminal (forked) |\n\n| Command | Description |\n|---|---|\n`/plan` |\nPlan mode for complex tasks |\n`/explore` |\nExplore codebase to answer questions |\n`/loop` |\nRun iteratively until task complete |\n`/model` |\nSwitch Sonnet / Opus / Haiku |\n`/provider` |\nSwitch AI provider (Claude / OpenCode) |\n`/mode` |\nToggle streaming / wait |\n`/terminalui` |\nToggle terminal-style display |\n\n| Command | Description |\n|---|---|\n`/access` |\nList pending / approved / blocked users |\n`/allow_user` |\nWhitelist a user + open permission/folder setup |\n`/permissions` |\nSet a user's permissions & folders |\n`/sandbox_folder` |\nMulti-select folders to sandbox a user |\n`/answer_policy` |\nConfigure when the bot answers (alias / reply / @mention, or everything) |\n`/approval_timeout` |\nHow long approval requests wait — 5m…3h presets or ♾️ unlimited |\n`/deny_user` |\nDeny a request or revoke access |\n`/block_user` |\nHard-block a user (bot ignores them completely) |\n\n| Command | Description |\n|---|---|\n`/reddit` |\nFetch Reddit posts, subreddits, profiles |\n`/vreddit` |\nDownload Reddit-hosted videos |\n`/medium` |\nFetch Medium articles via Freedium |\n`/file` |\nDownload a project file |\n`/telegraph` |\nToggle Instant View for long responses |\n`/extract <url>` |\nDownload media from YouTube, TikTok, Instagram |\n\n| Command | Description |\n|---|---|\n`/tts` |\nToggle voice replies, pick voice |\n`/transcribe` |\nTranscribe audio to text |\nSend voice note |\nAuto-transcribed → processed by Claude |\n\n| Command | Description |\n|---|---|\n`/ping` |\nHealth check |\n`/context` |\nShow Claude context / token usage |\n`/botstatus` |\nBot process status |\n`/restartbot` |\nRestart the bot |\n`/cancel` |\nCancel current request |\n`/commands` |\nShow all commands |\n`/softreset` |\nSoft reset (cancel + clear session) |\n\nHasharot is built for *hashar* — many people getting work done together. The core primitive is **Telegram forum Topics**: in a supergroup with Topics enabled, **every topic runs as a fully independent session** with its own project, model, and conversation memory. Zero configuration needed.\n\n```\n  🏠 General      — announcements, coordination (bot stays quiet unless addressed)\n  🎨 Frontender   — pinned to the frontend project\n  ⚙️ Backender    — pinned to the backend project\n  🚀 DevOps       — pinned to infra / deploy scripts\n  🧪 QA           — pinned to the test suite\n```\n\n**Create a topic** for each role or workstream (Frontender, Backender, DevOps, …).**Pin a project** inside each topic with`/project`\n\n(or set it once with`/default`\n\n) — the topic remembers it.**Work in parallel**— a long-running task in the Backender topic never blocks or pollutes the Frontender topic's context. Each teammate talks to the agent in their own lane.**Sandbox teammates**(owner) — grant each user their own folder with`/sandbox_folder`\n\n, so the Frontender can only touch the frontend project even if they wander into another topic.\n\nTip:keep one \"General\" topic un-pinned for coordination. By default the bot stays silent in group chats until directly addressed — by an alias name, a reply to its message, or an @mention. The owner tunes all of this live with: toggle each trigger on/off, add/remove alias names, or switch to answer-everything mode (with a warning — it will reply to normal human conversation too).`/answer_policy`\n\nToday the cleanest pattern is **one topic per person per project** (e.g. `myapp — Alice`\n\n, `myapp — Bob`\n\n) — each gets an independent session over the same folder. True parallel *editing* isolation is on the roadmap below.\n\n**Reddit — **`/reddit`\n\n& `/vreddit`\n\n`/reddit`\n\n& `/vreddit`\n\n`/reddit`\n\nis now a pure TypeScript module using Reddit's OAuth2 API directly — no external Python dependency.\n\n```\n# .env\nREDDIT_CLIENT_ID=your_client_id\nREDDIT_CLIENT_SECRET=your_client_secret\nREDDIT_USERNAME=bot_account\nREDDIT_PASSWORD=bot_password\n```\n\nCreate a \"script\" app at [https://www.reddit.com/prefs/apps/](https://www.reddit.com/prefs/apps/). Use a dedicated bot account — NOT your personal credentials. Video downloads need `ffmpeg`\n\nand `ffprobe`\n\non your PATH.\n\n**Medium — **`/medium`\n\n`/medium`\n\nPure TypeScript via Freedium mirror — no extra dependencies.\n\n```\n# .env (optional tuning)\nFREEDIUM_HOST=freedium-mirror.cfd\nMEDIUM_TIMEOUT_MS=15000\n```\n\n**Voice Transcription — Groq Whisper**\n\n```\n# .env\nGROQ_API_KEY=your_groq_key\nGROQ_TRANSCRIBE_PATH=/absolute/path/to/groq_transcribe.py\n```\n\n**Text-to-Speech — OpenAI TTS**\n\n```\n# .env\nOPENAI_API_KEY=your_openai_key\nTTS_MODEL=gpt-4o-mini-tts\nTTS_VOICE=coral\nTTS_RESPONSE_FORMAT=opus\n```\n\n13 voices available: `alloy`\n\n, `ash`\n\n, `ballad`\n\n, `cedar`\n\n, `coral`\n\n, `echo`\n\n, `fable`\n\n, `marin`\n\n, `nova`\n\n, `onyx`\n\n, `sage`\n\n, `shimmer`\n\n, `verse`\n\nAll config lives in `.env`\n\n. See [ .env.example](/Mamasodikov/hasharot/blob/main/.env.example) for the full annotated reference.\n\n| Variable | Description |\n|---|---|\n`TELEGRAM_BOT_TOKEN` |\nBot token from @BotFather |\n`ALLOWED_USER_IDS` |\nComma-separated Telegram user IDs |\n\n| Variable | Default | Description |\n|---|---|---|\n`ANTHROPIC_API_KEY` |\n— | API key (optional with Claude Max subscription) |\n`WORKSPACE_DIR` |\n`$HOME` |\nRoot directory for project picker |\n`CLAUDE_EXECUTABLE_PATH` |\n`claude` |\nPath to Claude Code CLI |\n`BOT_NAME` |\n`Hasharot` |\nBot name in system prompt |\n`STREAMING_MODE` |\n`streaming` |\n`streaming` or `wait` |\n`DANGEROUS_MODE` |\n`false` |\nAuto-approve all tool permissions |\n`CANCEL_ON_NEW_MESSAGE` |\n`false` |\nAuto-cancel running query on new message |\n`CLAUDE_SDK_LOG_LEVEL` |\n`off` |\nSDK log level: off, basic, verbose, trace |\n\n| Variable | Default | Description |\n|---|---|---|\n`REDDIT_CLIENT_ID` |\n— | Reddit OAuth2 client ID |\n`REDDIT_CLIENT_SECRET` |\n— | Reddit OAuth2 client secret |\n`REDDIT_USERNAME` |\n— | Reddit bot account username |\n`REDDIT_PASSWORD` |\n— | Reddit bot account password |\n`REDDIT_VIDEO_MAX_SIZE_MB` |\n`50` |\nMax video size before compression |\n`REDDITFETCH_TIMEOUT_MS` |\n`30000` |\nExecution timeout |\n`REDDITFETCH_JSON_THRESHOLD_CHARS` |\n`8000` |\nAuto-switch to JSON output |\n\n| Variable | Default | Description |\n|---|---|---|\n`FREEDIUM_HOST` |\n`freedium-mirror.cfd` |\nFreedium mirror host |\n`MEDIUM_TIMEOUT_MS` |\n`15000` |\nFetch timeout |\n`MEDIUM_FILE_THRESHOLD_CHARS` |\n`8000` |\nFile save threshold |\n\n| Variable | Default | Description |\n|---|---|---|\n`EXTRACT_ENABLED` |\n`true` |\nEnable /extract command |\n`YTDLP_COOKIES_PATH` |\n— | Netscape cookies.txt for yt-dlp |\n\n| Variable | Default | Description |\n|---|---|---|\n`GROQ_API_KEY` |\n— | Groq API key for Whisper |\n`GROQ_TRANSCRIBE_PATH` |\n— | Path to `groq_transcribe.py` |\n`OPENAI_API_KEY` |\n— | OpenAI API key for TTS |\n`TTS_VOICE` |\n`coral` |\nDefault TTS voice |\n`TTS_MODEL` |\n`gpt-4o-mini-tts` |\nTTS model |\n`VOICE_SHOW_TRANSCRIPT` |\n`true` |\nShow transcript text before agent response |\n\n```\nsrc/\n├── bot/\n│   ├── bot.ts                     # Bot setup, handler registration\n│   ├── handlers/\n│   │   ├── command.handler.ts     # All slash commands + inline keyboards\n│   │   ├── message.handler.ts     # Text routing, ForceReply dispatch\n│   │   ├── voice.handler.ts       # Voice download, transcription, agent relay\n│   │   └── photo.handler.ts       # Image save + agent notification\n│   └── middleware/\n│       ├── auth.middleware.ts      # User whitelist + group chat auth\n│       └── stale-filter.ts        # Ignore stale messages on restart\n├── claude/\n│   ├── agent.ts                   # Claude Agent SDK, session resume, system prompt\n│   ├── mcp-tools.ts              # MCP server: Reddit, Medium, Extract, Telegraph tools\n│   ├── session-manager.ts         # Per-chat session state\n│   ├── session-history.ts         # Session persistence and history\n│   ├── request-queue.ts           # Sequential request queue\n│   ├── command-parser.ts          # Help text + command descriptions\n│   └── agent-watchdog.ts          # Watchdog for long-running agent tasks\n├── reddit/\n│   ├── redditfetch.ts             # Native TypeScript Reddit client (OAuth2)\n│   └── vreddit.ts                 # Reddit video download + compression pipeline\n├── medium/\n│   └── freedium.ts                # Freedium article fetcher\n├── media/\n│   └── extract.ts                 # YouTube/TikTok/Instagram extraction (yt-dlp)\n├── telegram/\n│   ├── message-sender.ts          # Streaming, chunking, Telegraph routing\n│   ├── markdown.ts                # MarkdownV2 escaping\n│   ├── telegraph.ts               # Telegraph Instant View client\n│   ├── telegraph-settings.ts      # Per-chat Telegraph toggle\n│   ├── terminal-renderer.ts       # Terminal-style UI renderer\n│   ├── terminal-settings.ts       # Per-chat terminal UI toggle\n│   └── deduplication.ts           # Message dedup\n├── tts/\n│   ├── tts.ts                     # TTS provider routing (Groq Orpheus / OpenAI)\n│   ├── tts-settings.ts            # Per-chat voice settings\n│   └── voice-reply.ts             # TTS hook for agent responses\n├── audio/\n│   └── transcribe.ts              # Shared transcription utilities\n├── utils/\n│   ├── download.ts                # URL download with SSRF protection\n│   ├── sanitize.ts                # Path and error sanitization\n│   ├── workspace-guard.ts         # Workspace boundary enforcement\n│   ├── url-guard.ts               # URL validation (protocol, SSRF)\n│   ├── file-type.ts               # File content validation\n│   ├── caffeinate.ts              # macOS sleep prevention\n│   ├── session-key.ts             # Session key generation (DM + forum topics)\n│   ├── agent-timer.ts             # Agent execution timing\n│   └── debug-agent.ts             # Debug utilities\n├── config.ts                      # Zod-validated environment config\n└── index.ts                       # Entry point\n```\n\nThe agent's context is assembled from **five layers** on every query (see `agent.ts`\n\n):\n\n| # | Layer | Source | Notes |\n|---|---|---|---|\n| 1 | Claude Code preset |\nAgent SDK (`preset: 'claude_code'` ) |\nThe same base system prompt as terminal Claude Code — Hasharot is a full agent, not an API wrapper |\n| 2 | Bot prompt (static) |\n`agent.ts` + `conduct.ts` |\nPersona guidelines, Telegram/Telegraph output formatting, access-model conduct rules, MCP tool usage hints |\n| 3 | `SYSTEM_PROMPT_FILE` |\nPath set in `.env` |\nOptional identity/memory file appended to every query. Re-read on change (mtime-cached) — edit it and the next message already uses it, no restart |\n| 4 | Speaker prompt (dynamic) |\nBuilt per message | Who is talking right now: name, group note, and their real access level (owner / sandboxed + folders / trusted) |\n| 5 | Claude Code memories |\n`settingSources: ['project', 'user']` |\n✅ Standard `CLAUDE.md` support — see below |\n\n**Project memory**— the`CLAUDE.md`\n\n(and`.claude/`\n\nsettings) of the**opened project folder** is loaded automatically. Every project carries its own memory: open`~/projects/myapp`\n\nand`myapp/CLAUDE.md`\n\nis in context for that chat.**User memory**—`~/.claude/CLAUDE.md`\n\n(the machine owner's global memory) is loaded in every session.**Conversation memory**— sessions live in Claude Code's own session store;`/continue`\n\nand`/resume`\n\nrestore the full history, and the working project is remembered per chat.\n\nTip:put project-specific instructions in that project's`CLAUDE.md`\n\n(picked up instantly per chat), and bot-wide personality/rules in the`SYSTEM_PROMPT_FILE`\n\n— both apply without restarting the bot.\n\n```\nnpm run dev          # Dev mode with hot reload (tsx watch)\nnpm run typecheck    # Type check only\nnpm run build        # Compile to dist/\nnpm start            # Run compiled build\n./scripts/hasharot-botctl.sh dev start      # Start dev mode\n./scripts/hasharot-botctl.sh dev restart     # Restart dev\n./scripts/hasharot-botctl.sh prod start      # Start production\n./scripts/hasharot-botctl.sh dev log         # Tail logs\n./scripts/hasharot-botctl.sh dev status      # Check if running\n```\n\nIf Hasharot is editing its own codebase, use **prod mode** to avoid hot-reload restarts:\n\n``` js\n./scripts/hasharot-botctl.sh prod start      # No hot reload\n# ... let Claude edit files ...\n./scripts/hasharot-botctl.sh prod restart     # Apply changes\n```\n\nThen `/continue`\n\nor `/resume`\n\nin Telegram to restore your session.\n\nProd runs compiled code.`prod start`\n\n/`restart`\n\nbuilds (`tsc`\n\n) first, so a restart always reflects the current source — a build error fails fast instead of serving a stale`dist/`\n\n.\n\nFor a bot that survives crashes and reboots, install the LaunchAgent template:\n\n```\ncp scripts/com.hasharot.bot.plist.example ~/Library/LaunchAgents/com.hasharot.bot.plist\n# edit the paths inside (repo dir + absolute `which node`), then:\nnpm run build\nlaunchctl load ~/Library/LaunchAgents/com.hasharot.bot.plist\n```\n\n`KeepAlive=true`\n\nrestarts the process on exit; `RunAtLoad`\n\nstarts it at login. Without a supervisor the bot stays down after a crash or reboot until manually restarted.\n\nAll state lives in `~/.hasharot`\n\n(access grants + per-user sandbox paths, sessions, settings). It's a single copy on one disk — losing `access-control.json`\n\nsilently revokes every approved teammate. Back it up (Time Machine covers it, or `tar czf hasharot-backup.tgz ~/.hasharot`\n\n).\n\n**User whitelist**— only approved Telegram IDs can interact; the owner (`OWNER_USER_ID`\n\n) approves everyone else**Per-user sandbox**— restricted users are jailed to an owner-granted folder allowlist, captured per-query (revoking mid-query can't loosen it); every file and shell op is path-checked with**symlink resolution**, and interpreters (`python -c`\n\n,`node -e`\n\n, …) and hidden-path escapes (`--output=/etc/x`\n\n) are routed to owner approval**Owner approval flow**— destructive or out-of-sandbox operations pause and ask the owner with Allow / Deny buttons, a clear** why**line (sandbox escape, destructive command, interpreter, …), and a live ⏳ countdown; posted both in the originating chat and the owner's DM — deciding in either place closes both. Timeout configurable via`/approval_timeout`\n\n(presets or unlimited)**Env isolation**— the bot's own secrets (bot token, API keys) are stripped from the agent subprocess environment** Crash safety**— process-level handlers + inactivity watchdog free a wedged chat; atomic writes protect every JSON store** Dangerous mode**— opt-in auto-approve for all tool permissions (disables the above — use only on a fully trusted single-user box)** Secrets**— loaded from`.env`\n\n(gitignored), never committed\n\nNote on the shell sandbox:the restricted-user Bash gate is best-effort defense-in-depth (lexical inspection + owner approval), not a kernel jail — the whole bot runs as your user. For hostile users, run Hasharot itself inside a container/VM. For a trusted team sharing one machine, the sandbox + approval flow is the intended boundary.\n\n| Doc | What's inside |\n|---|---|\n`docs/AGENT_SETUP.md` |\n\n`docs/ACCESS_CONTROL.md`\n\n`docs/UI_BEHAVIOR.md`\n\n`.env.example`\n\nMulti-user collaboration lands incrementally — each step only when the previous one hits its limits:\n\n-\n**Topics — parallel sessions***(works today, zero setup)*Every forum topic is an independent session. Per-role topics (Frontender, Backender, …) give a team parallel lanes with no code changes. -\n**Busy-fork***(next up)*When a shared project session is busy with someone else's query, show a**\"Fork\"** button that branches a personal session from the shared context. Better than blanket per-user sessions: the main team context stays intact, and the fork inherits everything up to that point. -\n**Worktree isolation***(when truly needed)*Per-user git worktrees so two people can*write code in the same repo*simultaneously without stepping on each other's working tree. Only worth the complexity once \"two devs, one repo, same time\" is a real daily need. -\n**OS-level command jail***(only if hosting untrusted users)*Today the restricted-user shell gate is best-effort (lexical inspection + owner approval), not a kernel jail — see the Security note above. If Hasharot ever needs to host genuinely untrusted users, run each restricted command inside a real sandbox (`sandbox-exec`\n\non macOS,`bwrap`\n\n/container on Linux) with the allowlist bind-mounted, instead of validating the command string. Larger architectural change; not needed for a trusted team sharing one machine.\n\n**Hasharot** 🐜 — *ishlaringizni hashar qilib bitiring.*\n\n*If this project is useful to you, consider giving it a ⭐*\n\nOriginally based on claudegram by NachoSEO.", "url": "https://wpnews.pro/news/hasharot-control-a-claude-code-agent-on-your-machine-from-telegram", "canonical_source": "https://github.com/Mamasodikov/hasharot", "published_at": "2026-07-11 05:41:01+00:00", "updated_at": "2026-07-11 06:29:04.398385+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools", "large-language-models", "ai-products"], "entities": ["Hasharot", "Claude Code", "Telegram", "Grammy Bot", "Claude Agent SDK", "Paperclip", "Mamasodikov"], "alternates": {"html": "https://wpnews.pro/news/hasharot-control-a-claude-code-agent-on-your-machine-from-telegram", "markdown": "https://wpnews.pro/news/hasharot-control-a-claude-code-agent-on-your-machine-from-telegram.md", "text": "https://wpnews.pro/news/hasharot-control-a-claude-code-agent-on-your-machine-from-telegram.txt", "jsonld": "https://wpnews.pro/news/hasharot-control-a-claude-code-agent-on-your-machine-from-telegram.jsonld"}}