---
LLM: Claude
type: blueprint
slug: telegram-claude
lang: ru
date: 2026-09-22
title: "Blueprint: Telegram + Claude"
tagline: Свой Telegram как память и руки агента — локальный индекс, поиск через MCP, отправка только после твоего ✅
description: Локальный демон индексирует твою переписку в SQLite, агент ищет по ней через MCP-инструменты, любое исходящее сообщение проходит через approval-карточку с use-once токеном, а бот становится карманным входом к агенту и к штабу с телефона. Данные — на твоей машине.
audience: Для тех, у кого 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 решает три проблемы одной системой:
1. **Поиск/анализ по своему Telegram** — Claude получает MCP-инструменты для full-text search, чтения чатов, поиска контактов
2. **Безопасный outbound** — Claude может предлагать сообщения от твоего имени, но физически отправляет только после твоего ✅ в Telegram-карточке с use-once токеном
3. **Pocket Claude** — отдельный bot становится chat-интерфейсом к Claude Code в твоём vault'е, доступным с телефона
4. **Штаб-контур** (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'у и мосту

## Как применить

1. Открой coding agent (Claude Code, Cursor, Codex) **в trusted directory**, где ты обычно держишь персональный код / эксперименты (НЕ в vault'е — там будут только логи)
2. Покажи ему этот Blueprint: «собери по этому Blueprint Telegram + Claude integration у меня»
3. Агент задаст вопросы из секции **Вопросы для адаптации**
4. Ответь про свою OS, vault, какие чаты критичные, как организовать always-on
5. Агент создаст project, реализует 4 фазы по очереди — каждая фаза самостоятельно ценна, можно остановиться на любой
6. После фазы 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        │
                └────────────────────────────┘
```

### Пять слоёв

1. **Read intelligence** — userbot indexer + FTS5 store + read API + MCP read-tools. Голосовые и кружочки транскрибируются локальным Whisper и попадают в тот же индекс. Claude может искать и читать, но не писать. Capability A.
2. **Outbound with approval** — propose-send через бота с use-once токенами и audit. Claude предлагает, ты одобряешь. Capability B.
3. **Inbound chat session** — бот = persistent Claude conversation с твоим vault как контекстом. Capability C.
4. **Cross-cutting** — owner-only checks, rate limits, kill switch, daily digest, audit log. Безопасность поверх всех слоёв.
5. **Штаб-контур** (Phase 5) — мост `@hq` к оркестратору, алерты в его инбокс, scoped-MCP для дополнительных агентов, второй бот-персона в группах. Это уже не «Telegram для одного агента», а Telegram как транспорт для команды агентов; каждая идентичность в демоне — со своим гейтом.

## Ключевые принципы

1. **Approval gate is the entire safety story.** Нет trusted-path для outbound. Любой код пути всегда через карточку с use-once токеном. Если кто-то предлагает «оптимизацию через bypass» — отказ.

2. **Owner-only на bot.** Approval bot принимает callback'и и DM'ы только от одного `chat_id` (твой собственный Telegram user_id). Любой посторонний — silent ignore (DM) или `Not authorized` toast (callbacks).

3. **Use-once токены, привязанные к содержимому.** Approval-token = (random nonce, chat_id, sha256(text), expires_at, used). При press-✅ daemon validates все четыре поля и атомарно ставит `used=true`. Подмена content или повторный send — отказ.

4. **Local-only по умолчанию.** HTTP API на `127.0.0.1`, MCP через stdio. Никаких cloud-сервисов в data path. Даже approval-bot работает через стандартный Bot API (через Telegram'овские серверы), но callback'и принимаются на локальный polling, не через webhook.

5. **Audit append-only.** Каждое событие (`PROPOSED`, `APPROVED`, `EDITED`, `SENT`, `SEND_FAILED`, `RATE_LIMITED`, `REJECTED`, `CANCELLED`, `TIMEOUT`) пишется в отдельную таблицу. Только INSERT, никогда UPDATE/DELETE. Reasoning: forensics после факапа.

6. **Rate limits как defence-in-depth.** Конфигурируемые caps: per-hour (например 30), per-minute (10), per-peer cooldown (3s). Triggered limits → `RATE_LIMITED` audit + reject, не throttle.

7. **Kill switch видимый.** Команда `/pause` через бот или CLI мгновенно остановит всё outbound. `/resume` — включит. Используется при подозрении на bug или пока разбираешься с инцидентом.

8. **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 при этом никуда не делся.)*

9. **Vault-as-context (Phase 4).** Coding-agent subprocess запускается в твоём knowledge-base directory. Он читает твой `CLAUDE.md`/`AGENTS.md`, видит вашу структуру, может call MCP-инструменты Telegram'а. Persistent session через `--resume` — конверсация копится.

10. **TOS hygiene.** Telegram tolerates personal userbots без spam/automation/scraping. Никаких mass-send, broadcast, scraping чатов в которых ты не member, обхода UI. Owner-only + rate limits — это и есть твоя защита.

11. **Use it, see what hurts.** После каждой фазы — soak period. Реальные friction-points добавляются в backlog, не плановые refactors. Code review до merge — да; pre-emptive optimization — нет.

12. **Одна идентичность — один гейт (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 может предлагать сообщения, ты одобряешь.

**Что нужно решить:**
- Имя бота (что-то опознаваемое: `@MyClaudeApprovalBot` etc.)
- Где хранить 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 (тг-сессия)

**Что строится:**
- `tgsession` package: `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**: `launchd` plist в `~/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 via `EnvironmentVariables` в plist.
- **Sleep**: при закрытом крышке — daemon продолжит, MTProto-клиент догонит через `getDifference` после wake.

### Linux
- **Always-on**: `systemd` user 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`/`codex` CLI установленным
- 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 (`mcp` package на 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.

### Окружение
1. **OS**: macOS / Linux / Windows / Docker host?
2. **Always-on механизм**: launchd / systemd / Task Scheduler / Docker / WSL2 / vps?
3. **Где код проекта**: какая директория для repo (НЕ внутри vault)?
4. **Где vault / knowledge base**: путь? (нужно для Phase 4)
5. **Где data dir**: предпочтения по конкретному пути или OS-default?
6. **Какой язык / стек**: Python / JS / Go / другой?

### Telegram
7. **API credentials**: уже есть `api_id` + `api_hash` от my.telegram.org? Если нет — создать app в первую очередь.
8. **Phone number / аккаунт**: с каким номером проходит authentication? Рекомендация — твой основной живой аккаунт, а не свежесозданный: новый аккаунт + резкая автоматизация = выше риск флага.
9. **Backfill depth**: сколько дней назад индексировать при первом запуске? (рекомендация: 30 для активных юзеров, 7 для тяжёлых каналов)
10. **Approval bot username**: что-то предполагаемое? Будет создаваться в @BotFather после Phase 3.
11. **Твой Telegram user_id**: для owner-only check. Если не знаешь — узнаешь после Phase 1 запуска через `tg status` или прямой DB-query.
12. **Группы/каналы — outbound с самого начала или later?** Default — выключено, opt-in через config.
13. **Транскрибация голосовых**: нужна ли? Если да — какой Whisper-движок (mlx-whisper для Apple Silicon, faster-whisper / whisper.cpp для CPU/CUDA, либо cloud API для прототипа на не-чувствительных данных) и какой язык доминирует в твоих чатах?

### Coding agent
14. **Какой MCP-клиент** будет вызывать `tg_*` инструменты: Claude Code / Cursor / Codex / Gemini CLI / другой?
15. **Phase 4 agent CLI**: `claude` / `codex` / `gemini` / aider / другой? **Умеет ли resumable-сессии** (определяет стратегию памяти A/B/C в Phase 4)? Какая модель по умолчанию?
16. **Твой 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 мин)

1. Получить Telegram API app credentials на `https://my.telegram.org`
2. Coding agent создаёт project skeleton, реализует Phase 1
3. `tg setup` — авторизация через SMS + 2FA, session-файл сохраняется
4. `tg status` — verify всё подключилось, daemon запущен через выбранный always-on механизм
5. Backfill (30 дней по умолчанию) — займёт несколько минут на активном Telegram
6. Phase 2: HTTP API + MCP shim, регистрация MCP в coding-agent клиенте
7. Verify через MCP: `tg_search_messages("test")` возвращает результаты
8. Phase 3: создать @BotFather бота, сохранить токен в config, реализовать approval flow
9. Manual smoke: `tg propose <self_user_id> "hello" --timeout 60` → карточка в Saved Messages → ✅ → message received
10. 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):**
1. **Persistent in-flight state.** На старте демона помечать висящие `pending` как `timeout` и, по возможности, править ghost-карточки на «expired». Сейчас рестарт теряет in-flight.
2. **Atomic token store.** Если token store переедет из памяти в SQLite — переходить на `UPDATE ... WHERE used = 0` + проверку `rowcount`, вместо неатомарного check-then-set.
3. **Background-task done-callbacks.** Если polling бота умрёт (отозванный токен, сеть), демон жив, но outbound молча сломан. Нужен done-callback, который громко логирует и триггерит graceful stop.
4. **Server-side recipient resolution.** `recipient_username` / `recipient_name` сейчас приходят от вызывающего. Резолвить через БД (`users.get(chat_id)`), чтобы карточка всегда была доверенной.
5. **Медиа через approval.** `tg_propose_send` — только текст; файл/аудио — разовый скрипт на копии userbot-сессии вне approval-петли. Зеркало `send_file_after_approval` + тулза — ~50 строк, пока не понадобилось регулярно.

*Пункты 1–4 на 19.09.2026 не закрыты — в эксплуатации не болят настолько, чтобы обогнать продуктовые задачи.*

**Сам блюпринт (doc):**
1. Верифицировать **Cross-platform notes** на реальных Linux/Windows (сейчас — на основе общих знаний).
2. **Decision-tree для tech-stack** — flowchart «язык X + OS Y → этот SDK» вместо текстовых рекомендаций.
3. **Cost estimates** — RAM/CPU/disk демона, число API-калов coding-agent'а в Phase 4.
4. **Migration path** — как сосуществовать, если у пользователя уже есть Telegram-tooling (другой userbot, старый bot).
