- Volume was mounted at ~/.claude only, but claude-code writes auth to ~/.claude.json too — that file lived on the ephemeral container layer and was lost on every recreate. Now the whole $HOME is on the named volume, and claude-config moved outside HOME (/app) so it isn't shadowed by it. - Default /news topic was hardcoded to AI; now it's a configurable DEFAULT_TOPIC (plain "главные новости дня"), topic is fully free-form. - Prompt now instructs Claude to send interim "⏳ ..." progress updates via send_to_telegram while researching, not just the final digest — a bare request like "call this tool" was already taking 3+ minutes end-to-end, so silence read as broken. - All user-facing/prompt text moved into bot/lib/lexicon.dart. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
agent-news
Telegram-бот на Dart: по команде /news (или /news <тема>) запускает Claude Code
для ресёрча и присылает выжимку в чат. Тестовый/учебный проект — пока гоняем локально
в Docker, без деплоя в кластер.
Как это работает
Один контейнер, три процесса:
agent-news-bot(Dart, long polling) — слушает/news <тема>, спавнитclaudeкак сабпроцесс.claude(Claude Code CLI) — делает ресёрч; по ходу и в конце сам вызывает MCP-тулsend_to_telegram(промежуточные статусы + финальная выжимка).agent-news-mcp(Dart, stdio MCP-сервер) — спавнится самимclaude, шлёт готовый текст в Telegram Bot API.
Все тексты, которые бот показывает пользователю или подставляет в промпт Claude, лежат
в одном месте — bot/lib/lexicon.dart.
Запуск локально
cp .env.example .env
# заполнить TELEGRAM_BOT_TOKEN и ALLOWED_CHAT_IDS (через запятую)
docker compose up -d --build
~/.claude (авторизация Claude Code) хранится в именованном volume claude-home —
переживает пересборку и рестарт контейнера.
Первичная авторизация Claude Code
Claude Code CLI использует OAuth-логин через Claude.ai (подписка, не API-ключ). Один раз после первого запуска нужно зайти в контейнер и залогиниться:
docker compose exec agent-news claude auth login
CLI напечатает ссылку — открой её в браузере, авторизуйся, вставь код обратно в
терминал, если попросит. Учти: и ~/.claude/, и ~/.claude.json — оба нужны для
логина, поэтому в volume смонтирован весь /home/agent (см. docker-compose.yml),
не только ~/.claude/. После docker compose restart логин не слетит.
Проверка
Напиши боту /news <тема> (или просто /news — возьмёт DEFAULT_TOPIC) из чата с id
из ALLOWED_CHAT_IDS. Бот сразу ответит "начинаю…", дальше Claude сам присылает статусы
по ходу ресёрча и в конце — готовую выжимку, всё через send_to_telegram. Ресёрч
занимает несколько минут — это нормально, статусы как раз для этого.
docker compose logs -f agent-news
Локальная разработка (без Docker)
cd bot && dart pub get && dart analyze
cd ../mcp_server && dart pub get && dart analyze
Переменные окружения
| Переменная | Обязательна | Назначение |
|---|---|---|
TELEGRAM_BOT_TOKEN |
да | токен бота, используется и ботом, и MCP-сервером |
ALLOWED_CHAT_IDS |
да | список chat_id через запятую — кому отвечает бот |
DEFAULT_TOPIC |
нет | тема для /news без аргумента (по умолчанию — «главные новости дня») |
CLAUDE_TIMEOUT_SECONDS |
нет | таймаут на ресёрч (по умолчанию 600) |
MCP_CONFIG_PATH |
нет | путь к mcp.json (по умолчанию /app/claude-config/mcp.json) |