Для тех, у кого Telegram — основной канал общения, и кто хочет дать агенту доступ к переписке без стороннего сервиса и без риска, что он напишет что-то от твоего имени сам
Blueprint: Telegram + Claude
Прочитай до того, как строить. Личный Telegram-userbot по MTProto — серая зона Terms of Service: Telegram терпит личное использование, но не одобряет automation, spam и scraping. Session-файл = полный доступ к аккаунту: храни как секрет (chmod 0600, не в git, с бэкапом) — кто получил файл, получил твой Telegram целиком. Никаких mass-send, broadcast и scraping чатов, в которых ты не member. Любой outbound — только через approval gate: финальный ✅ всегда твой, никакого «trusted» пути в обход карточки.
Status: living. Все 4 базовые фазы реализованы и обкатаны в реальном использовании (месяцы in production), сверху с августа 2026 вырос пятый слой — штаб-контур: мост из Telegram к оркестратору (
@hq), алерты прод-ботов в инбокс оркестратора, scoped-MCP для второго агента и второй бот с собственной персоной для чужих групп. Архитектура, рабочие паттерны и грабли ниже — из практики, а не из плана. Документ прирастает по мере роста системы; v2.2 (19.09.2026) добавляет Phase 5 и правит дефолты, которые не выдержали эксплуатации (окно approval 5 → 30 мин).
Telegram копит твои разговоры годами — клиенты, друзья, рабочие чаты, каналы по теме. Поиск через Telegram UI слабый, граф связей теряется, а если ты не у компьютера — ты вне Claude. И при этом отдать Claude доступ к Telegram-account через сторонний сервис — нет, спасибо.
Этот Blueprint решает три проблемы одной системой:
- Поиск/анализ по своему Telegram — Claude получает MCP-инструменты для full-text search, чтения чатов, поиска контактов
- Безопасный outbound — Claude может предлагать сообщения от твоего имени, но физически отправляет только после твоего ✅ в Telegram-карточке с use-once токеном
- Pocket Claude — отдельный bot становится chat-интерфейсом к Claude Code в твоём vault’е, доступным с телефона
- Штаб-контур (Phase 5) — тот же бот становится входом к твоему оркестратору (
@hq …уходит не в карманную сессию, а в живую главную сессию агента), группа с алертами прод-ботов льётся в его инбокс, а второй бот с персоной живёт в чужих группах по белому списку
Данные — локально. Никаких сторонних сервисов с доступом к твоей переписке: индекс в SQLite на твоей машине, MCP-сервер на stdio, HTTP API на 127.0.0.1, approval bot для callback’ов через стандартный Telegram Bot API. Честная оговорка: инференс живёт там, где живёт твой агент — у Claude Code это API Anthropic, и всё, что агент читает из индекса, попадает в контекст модели. Это не «облачный сервис с доступом к переписке», но и не «ничего не покидает Mac»; для бота в чужой группе (Phase 5) это надо проговаривать участникам.
Что ты получишь
- Local daemon который индексирует все входящие сообщения в SQLite + FTS5 в реальном времени, плюс backfill за N дней при первом запуске
- MCP-инструменты для Claude в любом MCP-клиенте (Claude Code, Cursor, Codex): read-набор (
tg_search_messages,tg_search_contacts,tg_get_chat_info,tg_read_chat,tg_list_recent_chats), outbound (tg_propose_send), admin (tg_backfill_chat— подтянуть историю за пределами launch-окна,tg_transcribe_media— голосовые/кружочки → текст) и scoped-режим сервера (--scope digest: второй агент видит только каналы из правил дайджеста и тулзуtg_digest, а не всю переписку) - Транскрибация голосовых и видео-кружочков локальным Whisper (offline) — распознанный текст кэшируется в БД и становится searchable наравне с обычными сообщениями
- Approval bot в Telegram — Claude предлагает текст, ты получаешь карточку с
✅ Send / ✏️ Edit / ❌ Cancel, физическая отправка только после approve, токен use-once и привязан к(chat_id, sha256(text)) - Persistent chat-сессия с Claude через того же бота: пишешь DM → daemon spawn’ит coding-agent в твоём vault’е через
--resume, ответ возвращается reply’ем - Audit log каждого outbound-события + ежедневный digest
- Kill switch одной командой
- Мост к оркестратору (Phase 5): сообщение боту с префиксом
@hqминует карманную сессию и падает прямо в инбокс твоей главной агент-сессии; группа «Alerts» с админ-алертами прод-ботов — туда же - Второй бот с персоной для чужих групп (Phase 5): свой токен, свой белый список, свои таблицы; расшифровывает голосовые всем участникам, разбирает фото, рисует, делает итоги дня и напоминания — и физически не имеет доступа к индексу переписки, vault’у и мосту
Как применить
- Открой coding agent (Claude Code, Cursor, Codex) в trusted directory, где ты обычно держишь персональный код / эксперименты (НЕ в vault’е — там будут только логи)
- Покажи ему этот Blueprint: «собери по этому Blueprint Telegram + Claude integration у меня»
- Агент задаст вопросы из секции Вопросы для адаптации
- Ответь про свою OS, vault, какие чаты критичные, как организовать always-on
- Агент создаст project, реализует 4 фазы по очереди — каждая фаза самостоятельно ценна, можно остановиться на любой
- После фазы 3 ты заведёшь bot в @BotFather и скажешь его token агенту
Контекст: одна сессия coding-agent’а, отдельный git-репо для проекта (НЕ внутри vault), data-dir в OS-стандартном месте. Telegram API credentials получаются на my.telegram.org (нужны api_id + api_hash).
Когда использовать
- Telegram — твой основной канал коммуникации, и в нём копятся месяцы/годы переписки
- Поиск через Telegram UI тебя бесит (медленный, нет boolean, нет advanced syntax)
- Хочется задавать Claude вопросы по своей переписке: «что мы решили с X на прошлой неделе?», «найди контактов из Y», «дай дайджест канала Z»
- Хочется чтобы Claude мог писать с твоего account, но без риска разослать что-то странное — каждое сообщение через approval
- Хочется Claude-сессию доступной с телефона / в дороге — без терминала и без ssh
- Готов держать always-on daemon на своей машине (десктоп / NAS / VPS под твоим контролем)
Когда не использовать
- Telegram у тебя на минималках (несколько контактов, паблик-каналы), нет смысла
- Тебя устраивает Telegram UI search
- Ты не доверяешь идее «своего MTProto userbot’а» (Telegram tolerates personal use, но не одобряет — gray zone)
- Ты не хочешь держать always-on процесс — без daemon’а индекс отстаёт от реальности
Ключевая идея
Approval gate — единственный safety story для outbound. Userbot читает всё (он же — твой account через MTProto). Outbound идёт только через bot-side approval с use-once токенами. Никакого «trusted» пути в обход карточки. Если карточка сломалась — никто не пишет.
Разделение ролей:
Человек:
- Создаёт Telegram API credentials и approval bot (one-time setup)
- Получает approval-карточки в Saved Messages, нажимает ✅/✏️/❌
- Использует MCP-инструменты в coding agent’е для read-операций
- Пишет тому же боту чтобы говорить с Claude в vault’е (Phase 4)
- Решает, какие рабочие паттерны и расширения ему нужны (см. «Как мы работаем» / Roadmap)
Coding agent (Claude/Codex/etc.):
- Использует
tg_*MCP-инструменты для поиска/анализа Telegram - Предлагает outbound через
tg_propose_send— НИКОГДА не отправляет напрямую - В Phase 4 chat-сессии может вызвать любой
tg_*инструмент включая outbound (всё равно через approval)
Daemon (background):
- Индексирует входящие в реальном времени
- Держит approval-bot polling
- Spawn’ит coding-agent subprocess для chat-сессий
- Audit log, rate limits, kill switch — всё в нём
Архитектура
┌─────────────────────────────────┐
│ Твой Telegram account │
│ (private chats, groups, │
│ channels you subscribe to) │
└─────────────────┬───────────────┘
│ MTProto (userbot SDK)
▼
┌─────────────────────────────────────────────────┐
│ Local daemon (always-on background service) │
│ │
│ ┌──────────────┐ ┌────────────────────┐ │
│ │ Indexer │───→│ SQLite + FTS5 │ │
│ │ (New/Edit/ │ │ • messages │ │
│ │ Deleted) │ │ • transcripts │ │
│ │ + Whisper │ │ • chats / users │ │
│ │ transcribe │ │ • audit_log │ │
│ └──────────────┘ │ • approval_reqs │ │
│ └─────────┬──────────┘ │
│ │ │
│ ┌─────────────────────────────▼─────────┐ │
│ │ Local HTTP API (127.0.0.1, X-API-Key)│ │
│ │ /search /chats /outbound /control │ │
│ └─┬───────────────────┬───────────────┬─┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌──────────────┐ ┌──────────┐ │
│ │MCP shim │ │Approval bot │ │ CLI │ │
│ │(stdio, │ │(Bot API, │ │ commands │ │
│ │ 8 tools)│ │ separate │ │ for ops │ │
│ └────┬────┘ │ identity) │ └──────────┘ │
│ │ └──────┬───────┘ │
│ │ │ │
└───────┼────────────────┼────────────────────────┘
│ │
▼ │
Coding agent │
(Claude Code, │
Codex, Cursor...) │
│ │
┌──────▼──────┐ │ ✅ approve / chat
│tg_* tools │ │ ✏️ edit / ❌ cancel
│for read / │ │
│propose_send │ │ ┌────────────────────┐
└─────────────┘ └→│ Telegram (your │
│ Saved Messages or │
Phase 4 chat: │ bot's DM with you) │
Bot DM ───────────┐ └────────────────────┘
│
┌─────────▼──────────────────┐
│ Coding-agent subprocess │
│ (claude --print --resume) │
│ cwd = твой vault │
│ persistent session │
└────────────────────────────┘
Пять слоёв
- Read intelligence — userbot indexer + FTS5 store + read API + MCP read-tools. Голосовые и кружочки транскрибируются локальным Whisper и попадают в тот же индекс. Claude может искать и читать, но не писать. Capability A.
- Outbound with approval — propose-send через бота с use-once токенами и audit. Claude предлагает, ты одобряешь. Capability B.
- Inbound chat session — бот = persistent Claude conversation с твоим vault как контекстом. Capability C.
- Cross-cutting — owner-only checks, rate limits, kill switch, daily digest, audit log. Безопасность поверх всех слоёв.
- Штаб-контур (Phase 5) — мост
@hqк оркестратору, алерты в его инбокс, scoped-MCP для дополнительных агентов, второй бот-персона в группах. Это уже не «Telegram для одного агента», а Telegram как транспорт для команды агентов; каждая идентичность в демоне — со своим гейтом.
Ключевые принципы
-
Approval gate is the entire safety story. Нет trusted-path для outbound. Любой код пути всегда через карточку с use-once токеном. Если кто-то предлагает «оптимизацию через bypass» — отказ.
-
Owner-only на bot. Approval bot принимает callback’и и DM’ы только от одного
chat_id(твой собственный Telegram user_id). Любой посторонний — silent ignore (DM) илиNot authorizedtoast (callbacks). -
Use-once токены, привязанные к содержимому. Approval-token = (random nonce, chat_id, sha256(text), expires_at, used). При press-✅ daemon validates все четыре поля и атомарно ставит
used=true. Подмена content или повторный send — отказ. -
Local-only по умолчанию. HTTP API на
127.0.0.1, MCP через stdio. Никаких cloud-сервисов в data path. Даже approval-bot работает через стандартный Bot API (через Telegram’овские серверы), но callback’и принимаются на локальный polling, не через webhook. -
Audit append-only. Каждое событие (
PROPOSED,APPROVED,EDITED,SENT,SEND_FAILED,RATE_LIMITED,REJECTED,CANCELLED,TIMEOUT) пишется в отдельную таблицу. Только INSERT, никогда UPDATE/DELETE. Reasoning: forensics после факапа. -
Rate limits как defence-in-depth. Конфигурируемые caps: per-hour (например 30), per-minute (10), per-peer cooldown (3s). Triggered limits →
RATE_LIMITEDaudit + reject, не throttle. -
Kill switch видимый. Команда
/pauseчерез бот или CLI мгновенно остановит всё outbound./resume— включит. Используется при подозрении на bug или пока разбираешься с инцидентом. -
Group/channel writes — opt-in. В
config.yamlдефолтallow_groups: false,allow_channels: false. Phase 3 отказывает на group/channel пока не флипнули флаг. Reasoning: гораздо чувствительнее, blast radius шире. (В нашем инстансеallow_groupsвключён с 17.09.2026 — понадобился для постов в группу потока курса; approval gate при этом никуда не делся.) -
Vault-as-context (Phase 4). Coding-agent subprocess запускается в твоём knowledge-base directory. Он читает твой
CLAUDE.md/AGENTS.md, видит вашу структуру, может call MCP-инструменты Telegram’а. Persistent session через--resume— конверсация копится. -
TOS hygiene. Telegram tolerates personal userbots без spam/automation/scraping. Никаких mass-send, broadcast, scraping чатов в которых ты не member, обхода UI. Owner-only + rate limits — это и есть твоя защита.
-
Use it, see what hurts. После каждой фазы — soak period. Реальные friction-points добавляются в backlog, не плановые refactors. Code review до merge — да; pre-emptive optimization — нет.
-
Одна идентичность — один гейт (Phase 5). Когда в демоне живёт больше одного бота или больше одного агента-потребителя, у каждого свой оператор допуска первым в каждом хендлере: approval bot — только owner
chat_id; бот-персона — только группы из белого списка плюс личка владельца; второй агент через MCP — только--scope. Границы стерегут тесты (AST-тест «гейт первым оператором», boundary-тест «референт не трогаетmessages/vault/мост»), а не дисциплина.
Фазы
Четыре базовые фазы + пятая, штабная (появляется, когда Telegram становится транспортом для команды агентов, а не для одного). Каждая фаза самостоятельно ценна. Можно остановиться на любой. Реалистичный объём: каждая ~1-2 рабочих дня с coding agent’ом, ~15-25 задач, ~50-100 unit tests.
Phase 1 — Foundation (read intelligence)
Что строится:
- Project skeleton (separate git repo, не в vault)
- Telegram API credentials в config.yaml
- Userbot (MTProto client) — авторизация через SMS+2FA, session-файл хранится локально. Session-файл = полный доступ к аккаунту: храни как секрет (chmod 0600, не в git, сделай бэкап). Не запускай одну и ту же session из двух мест одновременно — Telegram видит конфликт и может ревокнуть сессию или флагнуть аккаунт
- Always-on daemon (см. Cross-platform notes ниже про OS-specific подъём)
- SQLite schema:
messages(+transcriptколонка для распознанного голоса) + FTS5 virtual table,chats,users,meta, плюс заранееaudit_logиapproval_requests(Phase 3 их будет использовать без миграций) - Real-time indexer на 3 события:
NewMessage,MessageEdited,MessageDeleted - Initial backfill за N дней при первом запуске (например 30), persisted-флаг чтобы не повторять. Backfill — батчами с паузами, не «всё за раз»: массовое чтение легко ловит
FloodWait(Telegram просит подождать N секунд) - CLI commands:
setup,status,search,contacts,chat
Capability A: ты можешь искать через CLI по своей переписке.
Что нужно решить:
- Какой MTProto-SDK для твоего языка (Python: Telethon / Pyrogram. JS: gramjs. Go: gotd. Rust: grammers)
- Где data-dir (см. вопросы)
- Сколько дней backfill’а
- Какие токенайзеры FTS5 поддерживает твой язык/SQLite (для русского + английского — обычно
unicode61 remove_diacritics 2)
Phase 2 — Local API + MCP integration
Что строится:
- HTTP server на
127.0.0.1:<port>, X-API-Key auth (auto-generated random key хранится в data dir с режимом 0600) - Endpoints:
POST /search/messages,POST /search/contacts,GET /chats/{id},GET /chats/{id}/messages,GET /chats/recent,GET /health,GET /stats - MCP shim — отдельный binary/script который подключается через stdio к coding agent’у. Внутри он делает HTTP calls на свой же local API
- 5 read MCP-инструментов:
tg_search_messages,tg_search_contacts,tg_get_chat_info,tg_read_chat,tg_list_recent_chats - Admin-инструменты (добавляются по мере использования, не обязательны для MVP):
tg_backfill_chat(history pull за пределами launch-окна черезiter_messages) иtg_transcribe_media(голосовые/кружочки → текст через локальный Whisper, результат кэшируется в БД и индексируется в FTS)
Capability A через Claude: Claude Code (или другой MCP-клиент) видит 5 read-инструментов и может ими пользоваться.
Что нужно решить:
- HTTP framework (Python: FastAPI/Starlette. JS: Hono/Express. Go: chi/Echo)
- MCP SDK (есть для Python, TypeScript, Go)
- Как хранить API key (генерится один раз, в data dir, не в repo)
Phase 3 — Outbound with approval
Что строится:
- Создание approval-bot через
@BotFather(one-time, твоё действие) - Bot SDK интегрирован в daemon (тот же процесс): aiogram (Python), grammY (JS), telegram-bot-api (Go) — что подходит языку
- Endpoints:
POST /outbound/propose,POST /control/pause,POST /control/resume - Storage primitives:
tokens.py(issue/validate/consume),audit.py(append-only writer),ratelimit.py(in-memory three-cap limiter),proposals.py(CRUD над approval_requests) - Approval card: HTML message с inline keyboard
✅ Send / ✏️ Edit / ❌ Cancel, callback_data =<action>:<proposal_id> - Orchestrator (state machine): propose → создаёт row, отправляет card, parks future, ждёт callback или timeout. На ✅ — issues token → validates → sender (через userbot) → audit
SENT - MCP tool:
tg_propose_send(chat_id, text, chat_type, ...)— long-poll на HTTP уровне до окна approval (у нас 30 минут), blocks в coding agent’е до решения - CLI:
tg propose,tg pause,tg resume,tg setup-bot
Capability B: Claude может предлагать сообщения, ты одобряешь.
Что нужно решить:
- Имя бота (что-то опознаваемое:
@MyClaudeApprovalBotetc.) - Где хранить bot token (config.yaml; data dir; encrypted)
- Default rate limits (рекомендация: 30/hr, 10/min, 3s/peer для personal use)
- Approval timeout (рекомендация: 30 минут default, настраиваемо; стартовали с 5 — не хватало, когда телефон не в руке: карточки протухали, агент повисал в ожидании)
- Группы/каналы — включать сразу или держать off?
Phase 4 — Inbound chat session (тг-сессия)
Что строится:
tgsessionpackage:meta.py(k-v session state в той же SQLite),transcript.py(per-session markdown writer),agent_runner.py(async-обёртка над coding-agent CLI — см. «Agent Runner» ниже),manager.py(lock + queue + state),formatting.py(Markdown → Telegram-HTML + length splitter),commands.py(/new /status /help renderers)- В daemon msg_handler: dispatch для
/new/status/help(новое) +/pause/resume(существующее) + plain text →manager.handle()→ Agent Runner - Per-session markdown transcript в отдельной папке внутри vault’а (например
Claude-tg-sessions/) — он же служит контекст-стором для стратегии B (ниже) - UX: ⚡ reaction на твоё сообщение (in progress), ⏳ если queued, “typing…” indicator пока агент работает, bot menu commands (
/new/status/helpпоявляются в Telegram menu кнопке) - Concurrency: lock + queue (max 5), 6+ → reject. Late replies (queued messages) приходят отдельным message в тот же чат
- (Опц.) 50% context warning: если CLI отдаёт usage-метаданные — когда cumulative tokens пересекли половину
contextWindow, добавить one-time prefix⚠️ контекст 50%+ (подумай о /new). Нет usage-метаданных — просто пропусти.
Agent Runner — контракт и стратегии (вот что делает Phase 4 переносимой)
Не привязывайся к одному CLI. Опиши Agent Runner как компонент с контрактом и реализуй под свой агент. Контракт:
- (обязательно) принять текст сообщения + working directory = vault → вернуть текстовый ответ;
- (желательно) держать контекст разговора между сообщениями;
- (опционально) вернуть метаданные:
session_id, token usage.
«Память между сообщениями» — три стратегии по убыванию предпочтения, выбираешь под возможности своего CLI:
| Стратегия | Когда | Как |
|---|---|---|
| A. Нативный resume | CLI умеет resumable-сессии (Claude Code: --resume <id>) |
Хранить session_id в meta, передавать на каждом запросе. Агент сам держит контекст. Дешевле всего по токенам. |
| B. Replay транскрипта | CLI делает one-shot без памяти (Codex exec, Gemini non-interactive, aider --message) |
Ты и так пишешь markdown-транскрипт — подавай его как контекст на каждый запрос (stdin / context-файл / --message). Работает с любым one-shot CLI; дороже по токенам. |
| C. Stateless one-shot | Минимальная реализация / простые вопросы | Каждое сообщение — независимый запрос без истории. Деградация UX, но заводится за час. |
Аналогично для остальных capability:
- System-prompt injection (проинструктировать: отвечает через Telegram, ≤4096 chars, лёгкий Markdown, без таблиц): нативный флаг если есть (
--append-system-prompt), иначе префиксь инструкцию в начало сообщения / context-файла. - session_id / usage: парсь из structured output, если CLI даёт JSON (
--output-format json); иначе генери свойsession_id(uuid) на стороне демона, а context-warning отключи.
Capability C: ты пишешь боту с телефона/планшета — агент отвечает с контекстом твоего vault’а.
Что нужно решить:
- Какой coding-agent CLI (
claudeот Anthropic,codexот OpenAI, gemini CLI, aider…) — и умеет ли он resumable-сессии (это и определяет стратегию A/B/C выше) - Где transcript-папка (внутри vault — recommended; для стратегии B это ещё и контекст-стор)
- Default model (если CLI multi-model): для coding-style вопросов — посильнее; для chit-chat — побыстрее/подешевле
- Таймаут subprocess (рекомендация: 10–20 минут — долгие сессии с большим контекстом реально упираются в маленький таймаут)
Phase 5 — Штаб-контур (оркестратор, алерты, второй бот)
Появляется, когда у тебя не «один агент с Telegram-тулзами», а команда агентов с главной сессией-оркестратором, и Telegram становится для неё транспортом. Пять независимых кусков, каждый включается отдельно:
5a. Мост к оркестратору (@hq). Сообщение approval-боту, начинающееся с @hq … (или @main …), перехватывается в коде демона до карманной тг-сессии и доставляется в живую главную сессию агента: либо в unix-сокет, который сессия публикует при старте, либо (дефолт, надёжнее) секцией ## TG <дата время> в append-only inbox-файл в vault’е, за которым главная сессия держит monitor. Ответ боту в Telegram — «Передал ✓ (сокет|инбокс)». Reasoning: карманная сессия — отдельный процесс без контекста оркестратора; штабу нужен прямой вход с телефона. Медиа-альбомы с подписью @hq идут старым путём через тг-сессию.
5b. Алерты в инбокс. Отдельная Telegram-группа «Alerts», куда прод-боты (сообщество, продукт) дублируют админ-алерты; userbot видит её как обычный чат, модуль alerts кладёт сообщения секциями ## ALERTS в тот же inbox-файл. Главная сессия верифицирует фактуру, действует и шлёт человеку только резюме «что случилось → что сделали». Каналы человека остаются дублем, не переездом.
5c. Scoped-MCP для второго агента. Тот же MCP-сервер, запущенный с --scope digest, отдаёт второму агенту (у нас — Codex, собирающий дайджест каналов) только каналы из правил дайджеста и тулзу tg_digest, а не всю переписку. Один демон, разные окна доступа по агенту.
5d. Второй бот с персоной для чужих групп. Отдельный Bot API-токен и отдельный Dispatcher в том же процессе (handle_signals=False у второго, иначе aiogram дерётся за сигналы). Свой контур: свои таблицы (скользящее окно 7 дней истории группы), свой гейт первым оператором — группа из белого списка allowed_chats или личка владельца, всё остальное молчит (fail-closed, пустой список = молчит везде). Privacy mode у бота выключен в BotFather, он читает всю группу и честно говорит это по /privacy. Умеет то, что нужно группе, а не владельцу: ответ по упоминанию/реплаю в персоне, автотранскрипт голосовых и кружочков локальным Whisper для всех участников, разбор фото, «нарисуй…», итоги дня, напоминания, шутки по контексту, консилиум персон, дуэль двух моделей. Артефакт «сделай дек из этой ветки» уходит секцией ## REFERENT в инбокс оркестратора, файл возвращается в группу через POST /referent/send_file (чат — только из таблицы задач, путь — только из белого списка папок). Кап расходов в день, rate limit, stale-фильтр апдейтов (Mac спал — старое только в память). Границы по построению: референт не прикасается к messages, vault’у, карманной сессии, MCP и мосту — это стерегут boundary-тесты.
5e. Карточки других контуров через тот же бот. Approval bot оказался удобной «почтой карточек» для всего штаба: почтовый вотчер шлёт через него карточки писем с кнопками, вотчер прода — алерты. Правило то же — кнопки принимает только owner.
Что нужно решить:
- Куда доставлять
@hq: сокет живой сессии (мгновенно, но зависит от того, что сессия жива) или inbox-файл с monitor’ом (переживает рестарты). Рекомендация: файл — дефолт, сокет — опционально. - Нужен ли второй бот вообще. Он даёт новое только в группе с другими людьми; для владельца всё то же делает карманная сессия. Не заводить «потому что можно».
- Что видит бот-персона и кому это проговорено: группа чужая, ответы уходят в API модели — участники должны знать.
Как мы работаем (рабочие паттерны)
Это та часть, ради которой система вообще существует. Четыре фазы выше — что построено; ниже — как этим живёшь день за днём. Паттерны описаны обобщённо (узнаваемые сценарии, не привязанные к конкретным чатам); реплики курсивом — иллюстрации, подставь свои.
Каждый паттерн: когда → что делает агент → инструменты → пример.
1. Research по своей переписке
- Когда: нужно вспомнить или найти что-то в собственной истории — «что мы решили с X», «найди контакты из Y», «дай дайджест канала Z за неделю».
- Агент: ищет по FTS, читает релевантные чаты, суммирует. Отдаёт выжимку, а не сырые тела сообщений (см. принципы приватности).
- Инструменты:
tg_search_messages,tg_search_contacts,tg_read_chat,tg_get_chat_info,tg_list_recent_chats. - Пример: «о чём договаривались с Игорем в последний раз?» → найти контакт → прочитать чат → саммари ключевых договорённостей.
2. Восстановление истории (backfill) перед research
- Когда: нужный чат/канал старше окна индексации (демон копит с момента запуска + N дней backfill при старте). Старая переписка просто отсутствует в индексе.
- Агент: подтягивает историю чата по требованию, затем работает с ней как с обычным индексом.
- Инструменты:
tg_backfill_chat→tg_search_messages/tg_read_chat. - Пример: «подними всю переписку с подрядчиком за полгода и найди, где согласовали смету».
3. Голос → текст перед поиском/саммари
- Когда: в чате важные голосовые или кружочки, которых нет в текстовом поиске.
- Агент: транскрибирует локальным Whisper (offline, кэш — каждый клип один раз), текст попадает в индекс, дальше — обычный research.
- Инструменты:
tg_transcribe_media→tg_search_messages/tg_read_chat. - Пример: «в чате созвона были только голосовые — расшифруй и собери список задач».
4. Ассистированный outbound от твоего имени
- Когда: «напиши X-у, что …» — агент формулирует сообщение от твоего лица.
- Агент: составляет текст с учётом контекста переписки →
tg_propose_send→ ждёт твой ✅ в карточке. Никогда не отправляет напрямую. - Инструменты:
tg_propose_send(+ read-инструменты для контекста). - Пример: «напиши Игорю, что встреча переносится на четверг» → карточка в Saved Messages → ✅ → отправлено.
5. Агент пишет от своего лица, представляясь
- Когда: ты хочешь, чтобы ответил сам агент, а не ты его руками — «ответь за меня», «пусть твой агент ему напишет». Агент не выдаёт себя за тебя: он представляется как твой AI-агент.
- Агент: читает контекст переписки, отвечает по сути от первого лица («это агент такого-то»), всё равно проходит через approval. Сам факт такого ответа — демонстрация того, что агент видит контекст и имеет доступы (чего нет у чата в вакууме).
- Инструменты:
tg_read_chat→tg_propose_send. - Пример: собеседник спрашивает «чем твой агент лучше обычного чат-бота?» — ты отвечаешь «пусть он сам и объяснит», агент пишет ему напрямую, на ходу доказывая разницу.
6. Pocket Claude — работа с телефона
- Когда: ты не за компьютером, но нужно спросить или сделать что-то в своей базе знаний.
- Агент: пишешь боту DM → daemon поднимает coding-agent в твоём vault через
--resume→ ответ возвращается reply’ем. Сессия persistent,/newсбрасывает контекст. - Инструменты: тг-сессия (Phase 4) + любые
tg_*изнутри сессии. - Пример: из метро — «что у меня по календарю завтра и накидай тезисы к созвону».
7. Daily digest
- Когда: хочешь держать под контролем outbound-активность без ручной проверки логов.
- Система: в заданное время шлёт в approval-чат сводку (что предложено / отправлено / отклонено / таймаут за сутки).
- Инструменты: digest scheduler в демоне.
- Пример: утренняя сводка «вчера: 3 предложено, 2 отправлено, 1 отклонено».
8. Штаб с телефона (@hq)
- Когда: ты не у компьютера, а оркестратору нужно поручение или ответ — не карманной сессии, а той, что держит контекст и решения.
- Ты: пишешь боту
@hq выложи вчерашнюю запись— и получаешь «Передал ✓». - Система: демон кладёт секцию в inbox-файл, monitor главной сессии будит её, она делает и отвечает тебе через approval-карточку или в живом диалоге.
- Инструменты: мост в демоне + inbox-файл + monitor на стороне агента.
9. Бот в чужой группе
- Когда: в группе с друзьями/коллегами хочется «домашнего» бота: расшифровать голосовое всем, разобрать скрин, сделать итоги дня, пошутить в тон.
- Ты: добавляешь бота, вписываешь id группы в белый список, участникам говоришь, что ответы уходят в API модели.
- Система: отвечает только по обращению, помнит окно группы, к твоей переписке и vault’у доступа не имеет.
- Инструменты: Phase 5d.
Инвариант поверх всех паттернов: read-паттерны (1–3) полностью локальны — данные не покидают твою машину. Любой outbound (4–5) проходит через approval gate — финальный ✅ всегда твой, никаких исключений.
Cross-platform notes
macOS
- Always-on:
launchdplist в~/Library/LaunchAgents/<your-app>.plist. RunAtLoad=true, StartCalendarInterval для cron-like jobs (бэкап). - Data dir:
~/Library/Application Support/<app>/ - Coding-agent CLI: установка через
brewобычно. Path:/opt/homebrew/bin/<cli>(Apple Silicon) или/usr/local/bin/<cli>(Intel). - PATH gotcha: launchd subprocess НЕ наследует interactive shell PATH. Жёстко прописывай
<абсолютный путь>/cliв spawn-args, или установи env viaEnvironmentVariablesв plist. - Sleep: при закрытом крышке — daemon продолжит, MTProto-клиент догонит через
getDifferenceпосле wake.
Linux
- Always-on:
systemduser unit в~/.config/systemd/user/<app>.service(systemctl --user enable --now <app>) — recommended если десктоп/server. Альтернативы: supervisord, runit. - Data dir:
~/.local/share/<app>/(XDG-spec) или$XDG_DATA_HOME/<app>/. - Coding-agent CLI: install через npm/pip/curl, path обычно
/usr/local/bin/или~/.local/bin/. - PATH gotcha: systemd user services обычно наследуют user environment если
Type=simpleбезUser=overrides — но всё равно лучше абсолютный путь в spawn-args. - Headless server: вообще удобнее — никакого sleep, никаких VPN-проблем.
Windows
- Always-on: вариантов несколько, выбирать по комфорту:
- Task Scheduler — встроенный, можно настроить trigger “At log on” + “Restart on failure”, запуск как hidden window
- NSSM (Non-Sucking Service Manager) — обёртка сделать любую программу в Windows Service
- WSL2 — если ты Linux-фанат и хочешь systemd, WSL2 supports
systemd(нужно включить в.wslconfig). Bonus: одинаковый install как на Linux desktop
- Data dir:
%APPDATA%\<app>\(C:\Users\<you>\AppData\Roaming\<app>\) - Coding-agent CLI: установка зависит от CLI. Claude CLI — через
npm i -g @anthropic-ai/claude-codeили scoop. Codex — npm. Path в%USERPROFILE%\AppData\Roaming\npm\или scoop’е~\scoop\shims\. - Path separators: используй
pathlib.Path(Python) или эквивалент — никаких"/"в string-конкатенациях - Subprocess gotcha: Windows не любит
asyncio.subprocess.PIPEбезasyncio.WindowsProactorEventLoopPolicy. На Python 3.8+ это default, но verify - WSL2 alternative: запустить весь daemon внутри WSL2 — проще mental model, но coding-agent CLI должен быть тоже в WSL2 чтобы paths совпадали
Docker (универсально)
- Один контейнер с daemon (indexer + HTTP API + approval bot polling + tg-session subprocess host)
- Volume для data dir + vault dir
- Единственный gotcha: subprocess для coding-agent должен быть в том же image. Т.е. контейнер должен иметь
claude/codexCLI установленным - Plus: если ты на VPS / NAS — Docker самый чистый путь
- Минус: на Mac/Windows — overhead Docker Desktop, и Telethon/grammers всё-таки эффективнее напрямую
Tech stack — рекомендация по умолчанию
Если совсем без предпочтений — Python:
- Telethon (MTProto userbot) — зрелый, активный, кросс-платформенный
- aiogram 3.x (Bot API для approval bot) — async, чистый
- aiosqlite (SQLite async) — без отдельного DB-сервера
- FastAPI или Starlette (HTTP API)
- MCP SDK от Anthropic для Python (
mcppackage на PyPI) - pytest + pytest-asyncio
JS-фанат → Telethon-aналог gramjs + grammY (Bot API) + better-sqlite3 + Hono + MCP TypeScript SDK.
Go → gotd/td (MTProto) + go-telegram/bot (Bot API) + sqlite3 driver + chi/Echo + MCP Go SDK.
Вопросы для адаптации
Это центральная секция Blueprint. Coding agent должен задать эти вопросы пользователю до того как начнёт писать код. Без ответов реализация будет ломаться о specifics.
Окружение
- OS: macOS / Linux / Windows / Docker host?
- Always-on механизм: launchd / systemd / Task Scheduler / Docker / WSL2 / vps?
- Где код проекта: какая директория для repo (НЕ внутри vault)?
- Где vault / knowledge base: путь? (нужно для Phase 4)
- Где data dir: предпочтения по конкретному пути или OS-default?
- Какой язык / стек: Python / JS / Go / другой?
Telegram
- API credentials: уже есть
api_id+api_hashот my.telegram.org? Если нет — создать app в первую очередь. - Phone number / аккаунт: с каким номером проходит authentication? Рекомендация — твой основной живой аккаунт, а не свежесозданный: новый аккаунт + резкая автоматизация = выше риск флага.
- Backfill depth: сколько дней назад индексировать при первом запуске? (рекомендация: 30 для активных юзеров, 7 для тяжёлых каналов)
- Approval bot username: что-то предполагаемое? Будет создаваться в @BotFather после Phase 3.
- Твой Telegram user_id: для owner-only check. Если не знаешь — узнаешь после Phase 1 запуска через
tg statusили прямой DB-query. - Группы/каналы — outbound с самого начала или later? Default — выключено, opt-in через config.
- Транскрибация голосовых: нужна ли? Если да — какой Whisper-движок (mlx-whisper для Apple Silicon, faster-whisper / whisper.cpp для CPU/CUDA, либо cloud API для прототипа на не-чувствительных данных) и какой язык доминирует в твоих чатах?
Coding agent
- Какой MCP-клиент будет вызывать
tg_*инструменты: Claude Code / Cursor / Codex / Gemini CLI / другой? - Phase 4 agent CLI:
claude/codex/gemini/ aider / другой? Умеет ли resumable-сессии (определяет стратегию памяти A/B/C в Phase 4)? Какая модель по умолчанию? - Твой timezone (для daily digest и логов).
Возможные расширения (Roadmap)
Текущее использование описано в разделе «Как мы работаем». Ниже — то, что ещё не построено и требует отдельного дизайна (Phase 5+):
- Мониторинг конкретных каналов / чатов с keyword alerts (Claude тегает interesting message → ping в Saved Messages) — частично закрыто Phase 5b другим путём: алерты не по keyword, а по выделенной группе
- Background digests по темам («что было в AI-каналах за неделю»)
- Image OCR pipeline (картинки → текст в FTS5; голос уже сделан, см. паттерн 3)
- Cross-chat thread tracking (одна тема обсуждается в 5 чатах → консолидированный feed)
- Auto-categorization входящих (work / personal / promo / …)
- Templated outbound (
tg_compose <template> <recipient>для часто-повторяющихся заданий) - Multi-account support (личный + рабочий аккаунт в одной системе)
- Voice replies (TTS из ответа Claude → голосовое сообщение в bot-чате)
- Медиа через approval-карточку (
tg_propose_send_file: файл/аудио с тем же ✅) — сейчас бот шлёт только текст, медиа — разовым скриптом на userbot-сессии - Вторая волна бота-персоны: память между группами через семантический стор, радар по темам, регулярные итоги — только с согласия участников и белыми списками
Пользователь брейнстормит с агентом, какие из них relevant, и какие появятся новые из его реальной работы.
Нюансы и грабли
Из реальной эксплуатации — то, на чём спотыкаешься, и как не споткнуться.
- Окно approval в 5 минут — мало. Стартовали с 5, карточки протухали каждый раз, когда телефон не в руке, а агент повисал в long-poll впустую. 30 минут — рабочий дефолт; токен всё равно use-once.
- Approval-карточку надо успеть нажать. Токен живёт ограниченное окно (например 60 сек после выдачи), сам proposal — до timeout’а (минуты). Прозеваешь — статус
timeout, сообщение не уходит, и это правильно: молчаливая доотправка хуже промаха. Просто предложи заново. (Ловили вживую: карточка ушла, человек отвлёкся — пришлось повторять propose.) - Бот шлёт только текст. Approval-путь рассчитан на текст. Файл / фото / аудио через него не отправить. Workaround для разовой отправки медиа — отдельный скрипт на userbot-сессии (
send_file), вне approval-петли. Не прикручивай медиа к карточке «на лету». - Приватность: суммируй, не вываливай. Это личная переписка. Агент по умолчанию отдаёт выжимку, а не сырые тела сообщений в чат, и никогда не выгружает переписку во внешние сервисы.
database is locked. Обычно — два запущенных демона (orphan + launchd/systemd) дерутся за БД, либо длинная write-транзакция. WAL +busy_timeoutснимают 99%; если осталось — убей процесс-дубль.- In-flight state не переживает рестарт демона. Pending-proposals и активные тг-сессии живут в памяти. Рестарт посреди ожидания → HTTP-caller получает timeout, в чате остаётся «призрак»-карточка со старыми кнопками. Known follow-up: на старте помечать висящие pending как expired.
- FTS5 и спецсимволы. Дефисы, URL, спецсимволы ломают FTS5-синтаксис, если запрос не санитизировать (фразовое экранирование) — иначе search падает в 500. При этом advanced-синтаксис (кавычки,
*, AND/OR/NOT, NEAR) надо пропускать как есть. - Транскрибация: кэш и устойчивость к битым клипам. Распознал один раз → закэшировал в БД, больше не гоняешь. Батч голосовых не должен падать целиком из-за одного битого клипа — каждый обрабатывается изолированно.
- launchd/systemd не наследуют shell PATH. Subprocess coding-agent’а не найдёт
claude/codexпо имени. Прописывай абсолютный путь к CLI в spawn-args (детали — в Cross-platform notes). - Session-файл — ключ от аккаунта. Не коммить, не шарь, бэкапь, права 0600. Кто получил файл — получил твой Telegram целиком. Потеря/инвалидация = снова SMS+2FA.
- Одна session — одно место. Тот же session-файл, запущенный с двух машин/процессов, Telegram читает как конфликт → может ревокнуть сессию или флагнуть аккаунт. (Это про Telegram-сессию — в отличие от
database is locked, который про два демона на одной БД.) - FloodWait — уважай, не долби. При backfill / массовом чтении Telegram отвечает
FloodWaitErrorс числом секунд. SDK обычно ждёт сам, но не всегда — не ретрай агрессивно поверх. Backfill батчами с паузами; первый 30-дневный backfill на активном аккаунте — это реально много запросов. - Тесты — без живого Telegram. Те самые 50–100 тестов гоняй против фейкового MTProto-клиента (мокни интерфейс SDK, не реальную сеть) + in-memory SQLite. Дёргать настоящий Telegram из тестов — это и флаки, и FloodWait-риск.
- Два бота в одном процессе — второй
Dispatcherсhandle_signals=False. Иначе aiogram ставит обработчики сигналов дважды и демон не останавливается штатно. - Privacy mode бота меняется только с переустановкой в группу. После
/setprivacyв BotFather бота надо удалить из группы и добавить заново — иначе он продолжает видеть только упоминания. - Гейт — в каждом хендлере, а не «где-то в начале». Один раз owner-only check стоял в одном месте, новые хендлеры его обошли, и бот отвечал чужим личкам. Теперь гейт первым оператором в каждом хендлере, и это проверяет AST-тест.
- Mac спал — апдейты протухли. Бот в группе после сна ловит пачку старых сообщений; отвечать на них — спам. Stale-фильтр по возрасту апдейта: старое только в память, без ответа.
- Phase 4 завязана на возможности CLI. Нативный
--resumeесть не у всех агентов. Если твой CLI без resumable-сессий — не эмулируй его флагами, бери стратегию B (replay транскрипта), см. «Agent Runner» в Phase 4. - Agent Runner пишет в stdout, не в Telegram — петлю замыкает демон. Самый частый косяк при сборке Phase 4: агент «отвечает в консоль», а не в чат. Две причины. (1) CLI запущен в интерактивном режиме — гоняй его one-shot / non-interactive (
claude -p/codex exec/ aider--message), иначе агент открывает TUI и печатает в терминал, а не в захватываемый stdout. (2) Демон получил return value Agent Runner’а, но не отправил его обратно —bot.reply(answer)пропущен, вывод осел вdaemon.log. Замыкание петли «DM → Agent Runner →bot.reply(answer)» — обязательный явный шаг, не «само получится». Проверка: пишешь боту DM → ответ приходит в тот же чат, а не только в лог демона. (Ловили у человека, собиравшего по блюпринту: всё работало, но ответы уходили в консоль — не хватало замыкающего reply.)
TOS / Safety constraints
Personal Telegram userbot — gray zone в Terms of Service. Telegram tolerates личное использование, но не одобряет automation/spam/scraping. Что нельзя:
- Mass-send / broadcast — owner-only check + rate limits + approval gate. Каждое сообщение ручное (через ✅).
- Scraping channels you’re not in — userbot читает только то, в чём твой account уже member.
- Reverse-engineering Telegram UI / web client — никаких клиентских хаков, только официальный MTProto API.
- Automation that mimics a person — approval gate означает что финальный ✅ всегда твой; coding agent предлагает, ты решаешь.
- Sharing Telegram-data в сторонние сервисы — local-only design, MCP через stdio, HTTP на 127.0.0.1.
- Bot identity confusion — approval bot имеет явное имя бота, не претендует быть человеком.
Что можно и поощряется:
- Personal search / analytics своей переписки
- Local LLM-augmented assistant
- Approval-gated outbound от своего имени
- Backup своих сообщений (это твои данные)
Что НЕ входит в Blueprint (out of scope)
- Multi-account — система рассчитана на один Telegram account на инстанс. Можно поднять второй инстанс в другой data dir, но cross-account features (объединённый поиск, switching) не предусмотрено
- Web UI — никаких dashboards / browser-interfaces. Всё через CLI / MCP / Telegram bot
- Public bot service — approval bot owner-locked, нельзя превратить в shared service. Бот-персона для групп (Phase 5d) — не исключение из этого, а отдельная идентичность с отдельным гейтом; она тоже не публичный сервис, а бот в твоих группах по белому списку
- Cloud deployment — система предполагает контролируемую тобой машину (десктоп / NAS / VPS под твоим аккаунтом). Managed cloud сервисы выходят за рамки local-first design
- Persistent in-flight state — pending proposals / pending chat sessions живут в памяти. Daemon restart их теряет (HTTP caller получит timeout, ghost-карточки в чате). Это известное ограничение, фиксится в follow-up
- Real-time streaming output — chat-сессия выдаёт ответ полностью когда subprocess закончил. Streaming/typing-buffer — feature для Phase 5+
Workflow
Setup (one-time, ~30-60 мин)
- Получить Telegram API app credentials на
https://my.telegram.org - Coding agent создаёт project skeleton, реализует Phase 1
tg setup— авторизация через SMS + 2FA, session-файл сохраняетсяtg status— verify всё подключилось, daemon запущен через выбранный always-on механизм- Backfill (30 дней по умолчанию) — займёт несколько минут на активном Telegram
- Phase 2: HTTP API + MCP shim, регистрация MCP в coding-agent клиенте
- Verify через MCP:
tg_search_messages("test")возвращает результаты - Phase 3: создать @BotFather бота, сохранить токен в config, реализовать approval flow
- Manual smoke:
tg propose <self_user_id> "hello" --timeout 60→ карточка в Saved Messages → ✅ → message received - Phase 4: реализовать tgsession, restart daemon, написать боту первое сообщение
Daily use
- Read / research: в coding-agent (Claude Code/etc.) — «найди что обсуждали с Игорем по проекту X», «какие AI-каналы упоминали Y», и т.п. Claude использует MCP-инструменты.
- Outbound: «напиши Игорю что встреча перенеслась» — Claude вызывает
tg_propose_send, ты получаешь карточку, нажимаешь ✅/✏️/❌ - Pocket Claude (Phase 4): пишешь боту с телефона — «что у меня по календарю сегодня», «найди тот рецепт что я сохранял в избранном» — Claude отвечает в чате через subprocess в твоём vault’е
- Daily digest (если включен): в 09:00 (или твоё время) бот шлёт summary outbound-активности за сутки
Maintenance
tg pause/tg resume— kill switch когда что-то странное/newчерез бот — сбросить chat-сессию когда контекст устал- Daily backup DB через cron / launchd (Phase 1 supplement)
- Monitor
daemon.logдля FloodWait warnings (Telegram serverside rate limit’ы — обычно SDK сам обрабатывает, но stay alert)
Чеклист готовности
После всех 4 фаз и smoke test’а у тебя должно быть:
- Daemon запущен через always-on механизм твоей OS
- DB растёт (msg count увеличивается со временем)
- HTTP
/healthотвечаетok - MCP инструменты видны в coding-agent клиенте, search возвращает results
- Approval bot отвечает на
tg setup-bot - CLI
tg propose <self> "test"приводит к карточке в Saved Messages - Bot reaction (⚡), typing indicator, menu commands (
/new/status/help) работают - Audit log заполняется (sql
SELECT * FROM audit_log ORDER BY ts DESC LIMIT 20) - Group/channel write properly rejected (тест:
tg propose <group_id> "x" --type supergroup) - Kill switch работает (
tg pause→ propose →rejected,tg resume→ propose → ok) - (опц.) Транскрибация:
tg_transcribe_mediaна голосовом → распознанный текст появляется вtg_search_messages - (опц.) Backfill:
tg_backfill_chatподтягивает историю старше launch-окна
Реализация-пример
Референсная реализация (Python: Telethon + aiogram + FastAPI + MCP, все пять фаз, ~360 unit-тестов, транскрибация голосовых локальным Whisper, backfill истории, демон под launchd) — приватная; блюпринт описывает её архитектуру и грабли.
Известные follow-ups
Блюпринт живой — это не дыры, а осознанный backlog.
Система (engineering):
- Persistent in-flight state. На старте демона помечать висящие
pendingкакtimeoutи, по возможности, править ghost-карточки на «expired». Сейчас рестарт теряет in-flight. - Atomic token store. Если token store переедет из памяти в SQLite — переходить на
UPDATE ... WHERE used = 0+ проверкуrowcount, вместо неатомарного check-then-set. - Background-task done-callbacks. Если polling бота умрёт (отозванный токен, сеть), демон жив, но outbound молча сломан. Нужен done-callback, который громко логирует и триггерит graceful stop.
- Server-side recipient resolution.
recipient_username/recipient_nameсейчас приходят от вызывающего. Резолвить через БД (users.get(chat_id)), чтобы карточка всегда была доверенной. - Медиа через approval.
tg_propose_send— только текст; файл/аудио — разовый скрипт на копии userbot-сессии вне approval-петли. Зеркалоsend_file_after_approval+ тулза — ~50 строк, пока не понадобилось регулярно.
Пункты 1–4 на 19.09.2026 не закрыты — в эксплуатации не болят настолько, чтобы обогнать продуктовые задачи.
Сам блюпринт (doc):
- Верифицировать Cross-platform notes на реальных Linux/Windows (сейчас — на основе общих знаний).
- Decision-tree для tech-stack — flowchart «язык X + OS Y → этот SDK» вместо текстовых рекомендаций.
- Cost estimates — RAM/CPU/disk демона, число API-калов coding-agent’а в Phase 4.
- Migration path — как сосуществовать, если у пользователя уже есть Telegram-tooling (другой userbot, старый bot).