Scope down to local Docker testing, drop Gitea/K3s plumbing for now

This is a pilot project — running it via docker compose locally is enough
for now. Deploy/CI can come back once the project is greenlit for real use.

Also fixes claude invocation: add --strict-mcp-config (verified against
the actual installed claude-code CLI --help) so only agent-news' own MCP
server is loaded, not whatever else might be discoverable in the environment.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-21 20:48:30 +03:00
parent be09de2ad7
commit cb2041fc56
6 changed files with 52 additions and 74 deletions

2
.env.example Normal file
View File

@@ -0,0 +1,2 @@
TELEGRAM_BOT_TOKEN=
ALLOWED_CHAT_IDS=

View File

@@ -1,37 +0,0 @@
name: Build & Deploy
on:
push:
branches: [main]
env:
REGISTRY: registry.service.bearsdev.tech
IMAGE: agent-news
REPO: platformteam-projects/agent-news
jobs:
build:
runs-on: [ubuntu-latest]
steps:
- name: Build & Push
run: |
git clone https://gitea_admin:${{ secrets.CI_TOKEN }}@gitea.service.bearsdev.tech/${{ env.REPO }}.git app
cd app && git checkout ${{ gitea.sha }}
echo "${{ secrets.NEXUS_PASSWORD }}" | docker login ${{ env.REGISTRY }} -u "${{ secrets.NEXUS_USERNAME }}" --password-stdin
docker buildx build \
--builder default \
-f runner/Dockerfile \
-t ${{ env.REGISTRY }}/${{ env.IMAGE }}:${{ gitea.run_number }} \
-t ${{ env.REGISTRY }}/${{ env.IMAGE }}:latest \
--push .
- name: Update deploy repo
run: |
git clone https://gitea_admin:${{ secrets.CI_TOKEN }}@gitea.service.bearsdev.tech/deploy/${{ env.IMAGE }}.git deploy
cd deploy
sed -i "s|image: ${{ env.REGISTRY }}/${{ env.IMAGE }}:.*|image: ${{ env.REGISTRY }}/${{ env.IMAGE }}:${{ gitea.run_number }}|" deployment.yaml
git config user.email "ci@bearsdev.tech"
git config user.name "Gitea CI"
git add deployment.yaml
git commit -m "ci: update image to ${{ env.IMAGE }}:${{ gitea.run_number }}" || echo "no changes"
git push https://gitea_admin:${{ secrets.DEPLOY_TOKEN }}@gitea.service.bearsdev.tech/deploy/${{ env.IMAGE }}.git main

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
.dart_tool/
build/
.env

View File

@@ -1,33 +1,58 @@
# agent-news
Telegram-бот на Dart: по команде `/news` (или `/news <тема>`) запускает Claude Code
для ресёрча и присылает выжимку в чат. Учебный проект для platformteam — архитектура
и урок описаны в [aidoc](https://aidoc.platformteam.tech), страница `practices/agent-news-bot`.
для ресёрча и присылает выжимку в чат. Тестовый/учебный проект — пока гоняем локально
в Docker, без деплоя в кластер.
## Как это работает
Один под, один контейнер, три процесса:
Один контейнер, три процесса:
1. `agent-news-bot` (Dart, long polling) — слушает `/news`, спавнит `claude` как сабпроцесс.
2. `claude` (Claude Code CLI) — делает ресёрч, в конце вызывает MCP-тул `send_to_telegram`.
3. `agent-news-mcp` (Dart, stdio MCP-сервер) — спавнится самим `claude`, шлёт готовый
текст в Telegram Bot API.
Подробности и диаграммы — в уроке aidoc.
## Запуск локально
## Локальная разработка
```bash
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-ключ). Один раз
после первого запуска нужно зайти в контейнер и залогиниться:
```bash
docker compose exec agent-news claude
```
CLI напечатает ссылку — открой её в браузере, авторизуйся. Токен сохранится в
`~/.claude` на volume, так что после `docker compose restart` логин не слетит.
### Проверка
Напиши боту `/news` (или `/news <тема>`) из чата с id из `ALLOWED_CHAT_IDS` — бот
ответит "ищу…", а через 1-3 минуты Claude сам пришлёт выжимку через `send_to_telegram`.
```bash
docker compose logs -f agent-news
```
## Локальная разработка (без Docker)
```bash
cd bot && dart pub get && dart analyze
cd ../mcp_server && dart pub get && dart analyze
```
Сборка образа (контекст — корень репозитория):
```bash
docker build -f runner/Dockerfile -t agent-news:dev .
```
## Переменные окружения
| Переменная | Обязательна | Назначение |
@@ -37,29 +62,3 @@ docker build -f runner/Dockerfile -t agent-news:dev .
| `NEWS_PROMPT` | нет | промпт по умолчанию для `/news` без темы |
| `CLAUDE_TIMEOUT_SECONDS` | нет | таймаут на ресёрч (по умолчанию 360) |
| `MCP_CONFIG_PATH` | нет | путь к `mcp.json` (по умолчанию `/home/agent/claude-config/mcp.json`) |
## Первичная авторизация Claude Code
Claude Code CLI использует OAuth-логин через Claude.ai (подписка, не API-ключ). После
первого деплоя нужно один раз пройти логин внутри пода — иначе `claude -p ...` будет
падать с ошибкой авторизации:
```bash
kubectl exec -it -n platformteam deploy/agent-news -- claude
```
CLI напечатает ссылку — открой её в браузере, авторизуйся. Токен сохранится в
`~/.claude` (persist через PVC `agent-news-home`, см. `deploy/agent-news`), так что
после рестарта пода логин не слетит.
## Деплой
Стандартный BearsDev CI/CD (см. `bearsdev-systems/ai-agents/knowledge/cicd.md`):
`git push``.gitea/workflows/build.yaml` собирает и пушит образ → бампит тег в
`deploy/agent-news``.gitea/workflows/deploy.yaml` применяет манифест в K3s.
Перед первым деплоем вручную (см. план и `cicd.md`):
1. Создать `deploy/agent-news` репо с `deployment.yaml` + `.gitea/workflows/deploy.yaml`.
2. `kubectl apply -f pvc.yaml` — PVC `agent-news-home`, один раз, не через CI.
3. `kubectl create secret generic agent-news-secrets -n platformteam --from-literal=TELEGRAM_BOT_TOKEN=... --from-literal=ALLOWED_CHAT_IDS=...`
4. После первого деплоя — авторизация Claude Code (см. выше).

View File

@@ -41,6 +41,7 @@ class ClaudeRunner {
prompt,
'--mcp-config',
config.mcpConfigPath,
'--strict-mcp-config',
'--dangerously-skip-permissions',
],
environment: {'TELEGRAM_BOT_TOKEN': config.telegramToken},

12
docker-compose.yml Normal file
View File

@@ -0,0 +1,12 @@
services:
agent-news:
build:
context: .
dockerfile: runner/Dockerfile
env_file: .env
volumes:
- claude-home:/home/agent/.claude
restart: unless-stopped
volumes:
claude-home: