[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-1462":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":10,"rankLanguage":10,"license":22,"archived":23,"fork":23,"defaultBranch":24,"hasWiki":23,"hasPages":25,"topics":26,"createdAt":10,"pushedAt":10,"updatedAt":27,"readmeContent":28,"aiSummary":29,"trendingCount":16,"starSnapshotCount":16,"syncStatus":30,"lastSyncTime":31,"discoverSource":32},1462,"hermes-telegram-miniapp","clawvader-tech\u002Fhermes-telegram-miniapp","clawvader-tech","React SPA dashboard for Telegram Mini App v2.0 — 10-page mobile-first UI. Runs locally.","",null,"TypeScript",236,30,214,1,0,4,6,17,12,4.47,"MIT License",false,"main",true,[],"2026-06-12 02:00:28","# Hermes Telegram Mini App\n\nA sleek, terminal-style web interface for your Hermes agent that runs inside Telegram as a Mini App. Chat with your agent, manage cron jobs, and monitor system health — all from a dark-mode TUI that feels like home.\n\n## What you get\n\n- **Terminal chat** — streaming responses, slash commands, file attachments (images, PDFs, text)\n- **Context bar** — live model name, token usage bar, session duration (like the Hermes CLI)\n- **Status tab** — CPU\u002Fmem\u002Fdisk gauges, process list, quick actions\n- **Cron tab** — create, edit, delete, pause, and trigger scheduled jobs\n- **Agent spawning** — spawn independent Hermes instances in the background, monitor live output, send follow-up messages (interactive or one-shot mode, max 5 concurrent)\n- **File attachments** — attach images, PDFs, CSVs; agent uses vision_analyze or OCR automatically\n- **Local vision & OCR** — optional local LLM servers for private image analysis and document OCR\n- **Rock-solid auth** — dual HMAC-SHA256 + Ed25519 validation (Telegram's recommended method + third-party fallback)\n- **Security hardened** — CSP headers, XSS sanitization, auth rate limiting, SRI, CSPRNG session IDs (see [Security](#security))\n\n## Prerequisites\n\nBefore you start, you'll need:\n\n1. **Hermes Agent** installed and working (`hermes` CLI runs successfully)\n   - [Hermes Agent on GitHub](https:\u002F\u002Fgithub.com\u002FNousResearch\u002Fhermes-agent)\n   - Version 0.9.0 or later\n2. **A Telegram bot** — created via [@BotFather](https:\u002F\u002Ft.me\u002FBotFather)\n3. **Your Telegram user ID** — a number, not your username. Get it from [@userinfobot](https:\u002F\u002Ft.me\u002Fuserinfobot)\n4. **A publicly accessible URL** — either a Cloudflare tunnel, ngrok, or your own domain with SSL\n5. **Python `cryptography` package** — for Ed25519 signature validation\n   ```bash\n   pip install cryptography\n   ```\n\n## Setup\n\n### Step 1: Create a Telegram bot\n\n1. Open [@BotFather](https:\u002F\u002Ft.me\u002FBotFather) in Telegram\n2. Send `\u002Fnewbot`\n3. Pick a name (e.g. \"My Hermes Agent\")\n4. Pick a username ending in `bot` (e.g. `my_hermes_agent_bot`)\n5. **Save the bot token** — you'll need it. It looks like `123456789:ABCdefGHIjklMNOpqrsTUVwxyz`\n\n### Step 2: Get your Telegram user ID\n\n1. Open [@userinfobot](https:\u002F\u002Ft.me\u002Fuserinfobot)\n2. Send `\u002Fstart`\n3. It replies with your numeric ID (e.g. `9876543210`)\n4. **Save this number**\n\n### Step 3: Clone and build\n\n```bash\n# Clone the miniapp repo\ngit clone https:\u002F\u002Fgithub.com\u002Fclawvader-tech\u002Fhermes-telegram-miniapp.git\ncd hermes-telegram-miniapp\n\n# Build the frontend\ncd web && npm install && npm run build && cd ..\n```\n\n### Step 4: Deploy to your Hermes installation\n\n```bash\n# Deploy and install the auto-update hook (first time)\n.\u002Fdeploy.sh --install-hook\n```\n\nThis does four things:\n1. **Builds** the frontend from standalone repo source (includes Telegram initData injection, Chat\u002FAgents tabs)\n2. **Deploys** `web_server.py` and `web_dist\u002F` to your hermes-agent installation (with backup)\n3. **Installs a post-merge git hook** that auto-redeploys the mini app after every `hermes update`\n4. **Marks `web_server.py` as assume-unchanged** so `git status` stays clean\n\n**Why the hook?** `hermes update` pulls from the upstream NousResearch repo, which overwrites both `web_server.py` and `web\u002Fsrc\u002F` files (removing Telegram auth, Chat\u002FAgents tabs). The hook detects the update, rebuilds from standalone source, and re-deploys automatically.\n\nIf you prefer manual control (no hook):\n```bash\n.\u002Fdeploy.sh                           # Deploy with backup\n.\u002Fdeploy.sh --no-backup               # Deploy without backup\n```\n\n**Custom target directory:**\n```bash\nHERMES_AGENT_DIR=\u002Fpath\u002Fto\u002Fhermes-agent .\u002Fdeploy.sh --install-hook\n```\n\n### Step 5: Configure environment variables\n\nAdd these to `~\u002F.hermes\u002F.env` (create it if it doesn't exist):\n\n```bash\n# Required\nTELEGRAM_BOT_TOKEN=123456...wxyz\nTELEGRAM_OWNER_ID=9876543210\n\n# Generate a random API key for Bearer auth fallback:\n# python3 -c \"import secrets; print(secrets.token_urlsafe(32))\"\nAPI_SERVER_KEY=your_generated_key_here\n```\n\nIf you're using systemd to run the gateway, also add these to your service file. See `systemd\u002Fhermes-gateway.service` for a template.\n\n### Step 6: Expose the gateway to the internet\n\nThe mini app needs to be accessible from Telegram's servers. The Hermes gateway runs on port 9119 by default.\n\n**Option A: Cloudflare Quick Tunnel (fastest, but URL changes on restart)**\n\n```bash\ncloudflared tunnel --url http:\u002F\u002Flocalhost:9119\n```\n\nThis gives you a URL like `https:\u002F\u002Frandom-words.trycloudflare.com`. It works, but the URL changes every time you restart. Fine for testing.\n\n**Option B: Named Cloudflare Tunnel (recommended for production)**\n\n```bash\n# Login to Cloudflare\ncloudflared tunnel login\n\n# Create a named tunnel\ncloudflared tunnel create hermes\n\n# Route your domain to it\ncloudflared tunnel route dns hermes miniapp.yourdomain.com\n\n# Run the tunnel\ncloudflared tunnel run hermes\n```\n\nSee `tunnel\u002Fcloudflared-config.yml` for a sample config. Save it as `~\u002F.cloudflared\u002Fconfig.yml`.\n\n**Option C: Any other reverse proxy**\n\nJust forward HTTPS traffic to `localhost:9119`. You need a valid SSL certificate — Telegram requires HTTPS.\n\n### Step 7: Set the bot's Mini App URL\n\n1. Go back to [@BotFather](https:\u002F\u002Ft.me\u002FBotFather)\n2. Send `\u002Fsetmenubutton`\n3. Pick your bot\n4. Send the URL: `https:\u002F\u002Fyour-tunnel-url\u002F`\n\nThis adds a \"menu\" button in the chat that opens the mini app. Users tap it to launch the interface.\n\n### Step 8: Start the server\n\n```bash\ncd ~\u002F.hermes\u002Fhermes-agent && source venv\u002Fbin\u002Factivate\nnohup python -B -c \"from hermes_cli.web_server import start_server; start_server('127.0.0.1', 9119, False)\" > \u002Ftmp\u002Fhermes-dashboard.log 2>&1 &\n\n# Verify\ncurl -s http:\u002F\u002Flocalhost:9119\u002Fapi\u002Fstatus\n```\n\n### Step 9: Open it\n\n1. Open your bot in Telegram\n2. Tap the menu button (left of the text input)\n3. The mini app opens — you should see \"Hermes Agent\" with the context bar\n\nIf it asks for an API key, that means Telegram initData isn't reaching the server. See troubleshooting below.\n\n## How auth works\n\nThe mini app uses **dual validation**: HMAC-SHA256 (primary) + Ed25519 (fallback). Here's the flow:\n\n```\nTelegram Client                    Your Server\n     │                                │\n     │  1. User opens mini app        │\n     │  Telegram generates initData   │\n     │  (contains hash + signature)   │\n     │                                │\n     │  2. Mini app sends initData ──>│\n     │     via X-Telegram-Init-Data   │\n     │                                │\n     │                         3. Try HMAC-SHA256 (primary)\n     │                            secret = HMAC(key=\"WebAppData\", msg=bot_token)\n     │                            verify hash field\n     │                                │\n     │                         4. If HMAC fails, try Ed25519 (fallback)\n     │                            verify signature field with Telegram public key\n     │                                │\n     │                         5. Check user ID matches\n     │                            TELEGRAM_OWNER_ID\n     │                                │\n     │  \u003C── 6. Authenticated ──────── │\n     │                                │\n```\n\n**HMAC-SHA256** (primary) uses the bot token to derive a secret key. Per [Telegram docs](https:\u002F\u002Fcore.telegram.org\u002Fbots\u002Fwebapps#validating-data-received-via-the-mini-app): `secret_key = HMAC_SHA256(key=\"WebAppData\", msg=bot_token)`.\n\n**Ed25519** (fallback) uses Telegram's published public key — no bot token needed for verification. Useful for third-party validation.\n\nIf initData isn't available (e.g. you're testing in a regular browser), the server falls back to Bearer token auth using `API_SERVER_KEY`.\n\n## API endpoints used by the mini app\n\n| Endpoint | Auth | Purpose |\n|----------|------|---------|\n| `GET \u002Fapi\u002Fstatus` | None | Server status, gateway state, platform connections |\n| `GET \u002Fapi\u002Fhealth` | None | System health (CPU, memory, uptime) |\n| `GET \u002Fapi\u002Fauth\u002Fsession-token` | Telegram auth or localhost | Ephemeral session token for write ops |\n| `GET \u002Fapi\u002Fmodel-info` | Yes | Active model name, provider, context length |\n| `GET \u002Fapi\u002Fsession-usage` | Yes | Cumulative token usage for session |\n| `GET \u002Fapi\u002Fsessions` | Yes | Paginated session list |\n| `GET \u002Fapi\u002Fsessions\u002F{id}\u002Fmessages` | Yes | Session messages |\n| `DELETE \u002Fapi\u002Fsessions\u002F{id}` | Yes | Delete a session |\n| `GET \u002Fapi\u002Fcron\u002Fjobs` | Yes | List cron jobs |\n| `POST \u002Fapi\u002Fcron\u002Fjobs` | Yes | Create a new cron job |\n| `POST \u002Fapi\u002Fcron\u002Fjobs\u002F{id}\u002Fpause` | Yes | Pause a cron job |\n| `POST \u002Fapi\u002Fcron\u002Fjobs\u002F{id}\u002Fresume` | Yes | Resume a paused cron job |\n| `POST \u002Fapi\u002Fcron\u002Fjobs\u002F{id}\u002Ftrigger` | Yes | Trigger immediate execution |\n| `DELETE \u002Fapi\u002Fcron\u002Fjobs\u002F{id}` | Yes | Delete a cron job |\n| `POST \u002Fapi\u002Fcommand` | Yes | Execute a slash command |\n| `POST \u002Fv1\u002Fchat\u002Fcompletions` | Yes | Streaming chat (SSE), supports multimodal content |\n| `GET \u002Fapi\u002Fagents` | Yes | List spawned agents with live status |\n| `POST \u002Fapi\u002Fagents` | Yes | Spawn a new agent (interactive or one-shot) |\n| `GET \u002Fapi\u002Fagents\u002F{name}` | Yes | Agent details + tmux output |\n| `DELETE \u002Fapi\u002Fagents\u002F{name}` | Yes | Kill agent and remove from registry |\n| `POST \u002Fapi\u002Fagents\u002F{name}\u002Fmessage` | Yes | Send message to agent's tmux session |\n\n## Troubleshooting\n\n### \"Error 401\" when sending a message\n\nThis means Telegram initData validation is failing. Check:\n\n1. **Is `TELEGRAM_BOT_TOKEN` set correctly?** It's needed for HMAC-SHA256 validation (primary method) and bot ID extraction (Ed25519 fallback). Verify with: `curl https:\u002F\u002Fapi.telegram.org\u002Fbot\u003CTOKEN>\u002FgetMe`\n2. **Are you opening the mini app from Telegram?** initData is only generated inside Telegram's built-in browser. If you're opening the URL in Chrome\u002FSafari directly, there's no initData.\n3. **Is `TELEGRAM_OWNER_ID` your numeric ID?** Not your username — a number like `9876543210`.\n4. **HMAC argument order correct?** The server code must use `hmac.new(b\"WebAppData\", bot_token, sha256)` — NOT `hmac.new(bot_token, b\"WebAppData\", sha256)`. The Telegram docs use non-standard `HMAC_SHA256(msg, key)` notation which is easy to misread. See [this skill](https:\u002F\u002Fgithub.com\u002Fclawvader-tech\u002Fhermes-telegram-miniapp\u002Ftree\u002Fmain\u002F.hermes\u002Fskills\u002Fhermes-telegram-miniapp\u002FSKILL.md) for details.\n\n### \"Invalid API key\" on the cron\u002Fstatus tab\n\nThe cron tab uses Bearer token auth as a fallback. If you see this:\n\n1. Check that `API_SERVER_KEY` is set in your environment\n2. Make sure it matches what the mini app has stored (it auto-saves after first successful auth)\n3. Try clearing the mini app's local storage: open in Telegram → ... → Clear storage\n\n### Mini app loads but feels choppy\n\nThe keyboard animation uses `visualViewport` events for smooth transitions. This works in Telegram's built-in browser on iOS and Android. If you're testing in a desktop browser, the visual behavior may differ.\n\n### initData keeps expiring\n\nTelegram generates initData once when the mini app opens. It's valid for 24 hours. If you leave the app open overnight, you'll need to close and reopen it to get fresh initData.\n\n### Cloudflare tunnel URL changed\n\nFree `cloudflared tunnel --url` tunnels get a random URL each restart. For a stable URL, set up a named tunnel with your own domain (see Step 6, Option B).\n\n### Mini app broke after `hermes update`\n\nIf you run `hermes update` and the mini app stops working (401 errors, missing features):\n\n1. This happens because the upstream `hermes update` replaces `web_server.py` with the stock version (no Telegram auth)\n2. **Fix:** Redeploy and install the hook: `.\u002Fdeploy.sh --install-hook`\n3. The post-merge hook prevents this — it auto-redeploys after every `hermes update`\n4. If the hook is already installed but didn't fire, check: `cat ~\u002F.hermes\u002Fhermes-agent\u002F.git\u002Fhooks\u002Fpost-merge`\n\n### Upstream git pull overwrote custom files\n\nThis should not happen if the post-merge hook is installed. If it does:\n\n1. Redeploy: `cd ~\u002Fprojects\u002Ftelegram-miniapp-v2 && .\u002Fdeploy.sh`\n2. Reinstall the hook: `.\u002Fdeploy.sh --install-hook`\n3. Restart the server after redeploying\n\n## Architecture\n\n> **[View the interactive architecture diagram →](docs\u002Fminiapp-v2-architecture.html)**\n\n```\nTelegram Client\n    │\n    ├── Mini App (React SPA — Vite + TypeScript + Tailwind)\n    │   ├─ Sends initData via X-Telegram-Init-Data header\n    │   ├─ Falls back to Bearer token for non-Telegram browsers\n    │   └─ Built SPA served from hermes_cli\u002Fweb_dist\u002F\n    │\n    ▼\nCloudflare Tunnel (or any HTTPS reverse proxy)\n    │\n    ▼\nFastAPI Web Server (port 9119)\n    ├─ Dual auth: Ed25519 (primary) + HMAC-SHA256 (fallback)\n    ├─ Owner-only access control\n    ├─ Serves mini app static files from hermes_cli\u002Fweb_dist\u002F\n    ├─ Multimodal chat (images, PDFs, text files)\n    ├─ Attachment handling: saves to \u002Ftmp, injects tool hints\n    ├─ Agent spawning: tmux-backed independent Hermes instances\n    │   ├─ Interactive mode (full session, send follow-ups)\n    │   ├─ One-shot mode (hermes chat -q, auto-detects completion)\n    │   ├─ Worktree mode (-w) for parallel code work without conflicts\n    │   └─ Max 5 concurrent, auto-cleanup after 1 hour\n    └─ SSE streaming for chat responses\n\nStandalone Project Repo\n    ├─ Source: ~\u002Fprojects\u002Ftelegram-miniapp-v2\u002F\n    ├─ Deploy: .\u002Fdeploy.sh → copies to hermes-agent installation\n    └─ Protected: assume-unchanged flag prevents git pull overwrites\n\nOptional Local Models (CPU)\n    ├─ LFM2-VL-450M (port 8080) — image description & analysis\n    └─ GLM-OCR (port 8081) — OCR, tables, formulas, structured extraction\n```\n\n## Security\n\nv2.0.4 replaces tmux-based chat polling with direct Gateway API SSE streaming for instant responses and true abort support. v2.0.3 fixes a critical deploy issue where `hermes update` overwrites `web\u002Fsrc\u002F` files (removing Telegram initData injection and Chat\u002FAgents tabs). The deploy script now builds from the standalone repo source and syncs all `web\u002Fsrc\u002F` files. v2.0.1 addressed a critical HMAC validation bug. v2.0.0\u002Fv1.0.3 addressed 11 vulnerabilities from a full security audit. Here's what's protected:\n\n| Layer | Protection |\n|-------|-----------|\n| **Auth validation** | Dual HMAC-SHA256 + Ed25519 initData validation with correct key\u002Fmessage argument order |\n| **XSS** | All user-generated content (markdown, URLs, image sources, command names) sanitized via `esc()` before rendering. Only `http:\u002F\u002F`, `https:\u002F\u002F`, `mailto:` URL schemes allowed in links |\n| **CSP** | Strict Content-Security-Policy via `\u003Cmeta>` tag — blocks inline eval, external scripts (except Telegram SDK), unauthorized connections, and all framing (`frame-ancestors 'none'`) |\n| **Auth brute-force** | Per-IP rate limiter: 10 failed auth attempts per 60s triggers a 15-minute lockout (HTTP 429). Tracks failures across all authenticated endpoints |\n| **Token replay** | initData freshness reduced from 24h to 5 min, limiting replay window even if intercepted |\n| **Credential storage** | Bearer tokens stored in `sessionStorage` (clears on tab close), not `localStorage`. Telegram context uses native `CloudStorage` |\n| **Session IDs** | Generated with `crypto.randomUUID()` (CSPRNG), not `Math.random()` |\n| **Error disclosure** | Auth errors return generic messages; exception details logged server-side only |\n| **CDN integrity** | Telegram SDK loaded with Subresource Integrity (`integrity` + `crossorigin=\"anonymous\"`) |\n\n### Reporting\n\nFound a vulnerability? Please disclose responsibly by opening a private issue or contacting the maintainer directly.\n\n## Contributing\n\nFound a bug? Have an idea? Contributions are welcome.\n\n1. Fork the repo\n2. Make your changes (frontend in `web\u002F`, backend in `hermes_cli\u002Fweb_server.py`)\n3. Build the frontend: `cd web && npm run build`\n4. Open a PR\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","Hermes Telegram Mini App 是一个基于React的单页面应用，专为Telegram迷你程序设计，提供了一个具有10个页面、移动优先的用户界面，并支持本地运行。该项目采用TypeScript开发，具备终端聊天功能，包括流式响应、斜杠命令以及文件附件；同时提供了上下文栏展示实时模型名称与会话信息、状态页监控系统健康状况及Cron任务管理等功能。特别适合需要通过Telegram与AI助手进行交互、执行定时任务并保持系统监控的个人或团队使用。其安全特性如双重身份验证机制和XSS防护确保了数据传输的安全性。",2,"2026-06-11 02:43:54","CREATED_QUERY"]