Автосводка дня из ActivityWatch: пошаговый гайд с конфигами | AiManual
AiManual Logo Ai / Manual.
18 Июн 2026 Гайд

Как настроить автосводку дня из ActivityWatch и других источников: полное руководство с конфигами

Научитесь собирать логи активности из ActivityWatch, RescueTime, календаря и Git, генерировать PDF-отчет и отправлять в Telegram. Полные конфиги и Python-скрипт

Реклама
cliv2

Вы закрываете ноутбук в 23:00 и понимаете, что за день сделали... ну, что-то делали. В голове каша. Час долбились с багом в CI/CD, полтора часа совещание, еще полчаса пролистывали тикеты безрезультатно. А в ежедневном стендапе надо выдать внятный список.

Я перепробовал все: от ручного заполнения блокнота до pomodoro-трекеров. Но реально работающий метод нашелся только когда я заставил машину саму собирать за меня все цифры. На 18 июня 2026 года лучшая связка — ActivityWatch + пара сторонних апишек + собственный скрипт на Python 3.13. И сейчас я покажу, как собрать такую систему за один вечер.

Дисклеймер: я не люблю длинные теоретические вступления. Если вы хотите просто скопировать готовый код и забыть о ручных отчетах — листайте вниз, там лежит полный конфиг. Но если не прочитаете про «почему» — потом будете проклинать меня за баги в 3 часа ночи.

Проблема: вы не помните, что сделали

Каждое утро я просыпался и смотрел на пустой экран daily-отчета. «Вчера работал над деплоем» — это не отчет, это плевок в лицо здравому смыслу. К вечеру мозг перетирает 80% деталей. Вы помните, что фикс поставили, но сколько времени ушло на ту самую доску в Jira? Фиг.

А если вы фрилансер или работаете на фиксированный час — без точного трекинга вы просто дарите свои деньги заказчику. Потому что на стендапе вы скажете «потратил 2 часа на задачу», а на самом деле 3,5. И никто не узнает, кроме вас.

Ручные трекеры вроде Toggl или Tmetric работают, но требуют дисциплины. Я — DevOps, у меня дисциплина кончилась еще в час ночи, когда я патчил продакшен под Red Bull. Поэтому я хочу, чтобы система собирала данные сама, а я только один раз настроил фильтры.

И да, я знаю про RescueTime, он собирает топ аппов. Но его данные — черный ящик. Ты не знаешь, почему он посчитал Slack как «продуктивность», а терминал — как «нейтральное». Поэтому лучшая база — ActivityWatch с открытым исходным кодом и собственной логикой.

Решение: три источника + один скрипт

Нам нужно собрать данные из трех слоев:

  1. Активность за компьютером — ActivityWatch (окна, приложения, заголовки). Из него мы вытащим таймлайны событий.
  2. Целенаправленные трекеры — RescueTime API или Toggl API (я использую RescueTime для классификации «продуктивно/нет»).
  3. Контекстуальные сервисы — Google Calendar (встречи) и GitHub/GitLab (коммиты и PR).

Скрипт на Python забирает данные за прошедший день, собирает в единый JSON, генерирует Markdown и, если нужно, экспортирует в PDF. В конце — шлет в Telegram через бота. Весь код я выложу под спойлером.

Важно: все API ключи храните в .env. Никогда не коммитьте их в репозиторий, даже если репо приватный. Один случайный push в публичный форк — и ваш RescueTime аккаунт может уйти в спам.

В этой статье я не буду разбирать установку ActivityWatch — с ней справится даже стажер. Если у вас его нет, скачайте с официального сайта (последняя версия 0.13 на июнь 2026). Там же есть watcher для Linux, macOS, Windows. Я работаю на macOS, но скрипт платформенно-независимый.

Пошаговый план за 40 минут

1 Настройка ActivityWatch и экспорт данных через REST API

ActivityWatch поднимает локальный сервер на порту 5600. API — это радость. Заберите данные за период:

import requests
from datetime import datetime, timedelta

aw_url = "http://localhost:5600"
# Получаем список bucket'ов (категорий событий)
fetch_buckets = requests.get(f"{aw_url}/api/0/buckets").json()
# Нас интересует bucket с активными окнами
window_bucket = [b for b in fetch_buckets if 'window' in b][0]
# Получаем события за последние 24 часа
events = requests.get(f"{aw_url}/api/0/buckets/{window_bucket}/events?start={datetime.utcnow()-timedelta(days=1)}&end={datetime.utcnow()}").json()

Обратите внимание: я использую UTC, а не локальное время. Потом скрипт сделает конвертацию. Иначе на границе дня будут сдвиги.

Вытаскиваем из событий: app имя, title окна, длительность. У ActivityWatch есть интересная фича — он считает не просто время между start и end, а вычитает периоды, когда вы отошли (экран заблокировался). Это ключевое отличие от сырых логов.

2 Забор данных из RescueTime и Google Calendar

RescueTime — платный, но у него есть бесплатный Daily Summary API. Выдает агрегированные данные по продуктивности (время на очень продуктивные, продуктивные, нейтральные, отвлекающие и очень отвлекающие категории).

import os
rt_key = os.getenv('RESCUETIME_API_KEY')
rt_url = f"https://www.rescuetime.com/anapi/daily_summary_feed?key={rt_key}&format=json"
rt_data = requests.get(rt_url).json()
# последний элемент — сегодняшний отчет (если день еще не закончился)

Но есть нюанс: RescueTime обновляется с задержкой до 2 часов. Если вы генерируете сводку в 23:00, данные могут быть не полными. Я ставлю cron на 7 утра следующего дня.

Календарь Google — через Google Calendar API (нужен OAuth). Но для простоты можно использовать iCal ссылку и парсить через icalendar:

import icalendar, requests
ics = requests.get("https://calendar.google.com/calendar/ical/.../basic.ics").text
cal = icalendar.Calendar.from_ical(ics)

Заберите события за вчера, отфильтруйте по времени. Отличный источник для заголовка «Встречи» в отчете.

Git-активность — через GitHub API. Получаем коммиты пользователя за день. Я обычно вытаскиваю первые строки сообщений коммитов и количество измененных файлов.

3 Генерация Markdown-отчета и превращение в PDF

Собираем все в одну структуру:

report = {
    "date": yesterday.isoformat(),
    "total_computer_time_hours": sum(events_durations),
    "top_apps": [
        {"name": "", "hours": 0}
    ],
    "productive_vs_distracting": {
        "productive": 0,
        "distracting": 0
    },
    "meetings": [
        {"title": "", "start": "", "end": ""}
    ],
    "git_commits": [
        {"repo": "", "message": ""}
    ]
}

Формируем Markdown. Вот мой любимый шаблон:

# Сводка дня: {date}

## Общее время за компьютером
{total_hours} часов

## Топ приложений
{apps_table}

## Продуктивность (RescueTime)
Продуктивно: {productive} ч
Отвлекающе: {distracting} ч

## Встречи
{meetings_list}

## Коммиты
{commits_list}

PDF удобно генерировать через weasyprint или md2pdf. Я использую weasyprint — он берет HTML, а не Markdown, поэтому сначала конвертирую Markdown в HTML через markdown2.

from weasyprint import HTML
HTML(string=html_report).write_pdf('summary.pdf')

Вуаля. Теперь у вас есть файл, который можно отправить себе в Telegram через бота (токен бота и chat_id берем из .env).

4 Запуск по крону и отправка в Telegram

Создаем Python-скрипт daily_summary.py. Прописываем cron (или launchd на macOS) на запуск каждый день в 7:00 утра:

# m h  dom mon dow   command
0 7 * * * cd /path/to/project && /usr/bin/python3 daily_summary.py >> /var/log/daily_summary.log 2>&1

Telegram-отправка через python-telegram-bot (v20.x):

import asyncio
from telegram import Bot

async def send():
    bot = Bot(token=os.environ['TELEGRAM_BOT_TOKEN'])
    with open('summary.pdf', 'rb') as f:
        await bot.send_document(chat_id=os.environ['TELEGRAM_CHAT_ID'], document=f)
asyncio.run(send())
💡
Совет: сделайте скрипт идемпотентным. Если запустить его дважды за один день, он не должен создавать дубликаты. Проверяйте, существует ли уже файл с датой, и перезаписывайте его.

Нюансы и типичные ошибки

1. ActivityWatch не видит все окна. Если вы работаете в полноэкранных приложениях (например, игре), watcher может не зафиксировать активность. Решение: поставьте дополнительный watcher на заголовки окон — ''aw-watcher-window'' на Linux, он цепляет лучше. Или используйте ''aw-watcher-afk'' для отслеживания бездействия.

2. RescueTime API имеет лимит — 200 запросов в день. Для одного человека хватит, но не злоупотребляйте. Кешируйте ответы хотя бы на час.

3. Разница часовых поясов. Если ваш сервер живет по UTC, а вы работаете в MSK (UTC+3), то запрос за «вчера» даст данные не за ваше вчера, а за смещенное. Я решаю это передачей параметра timezone_offset_hours в скрипт из переменной окружения.

4. PDF может не сформироваться из-за шрифтов. WeasyPrint требует шрифты, установленные в системе. У меня была проблема на macOS — пришлось доустанавливать fontconfig через brew и указывать путь к шрифтам.

5. Отсутствие асинхронности в cron. Не вызывайте asyncio.run() внутри cron скрипта, если в системе уже крутится event loop. Лучше сделать отдельный Python файл без async для простоты. Или используйте requests вместо httpx.

Кстати, если вам интересно, как я автоматизирую обход блокировок DNS для доступа к AI-сервисам без VPN — почитайте статью «Обход блокировок ChatGPT: автоматическое обновление DNS-правил через GitHub Actions без VPN». Там простой GitHub Actions, который вписывается в нашу философию «не делай руками то, что может сделать код».

Как не превратить систему в очередной трекер-заброшка

Самое трудное — не начать все это ненавидеть. Если вы каждый день будете получать отчет, который сообщает, что 4 часа вы сидели в Slack, а не писали код, — мотивация упадет к нулю. Я прошел через это.

Совет: сделайте отчет __полезным__. Добавьте в него не только «плохие» цифры (время в Minecraft), но и «хорошие» — количество закрытых задач, коммитов, мерджей. Пусть бот говорит: «Молодец, сегодня на 20% больше коммитов, чем в среднем за неделю». Я для этого добавляю вызов OpenAI API — прошу одним предложением оценить продуктивность дня. Это добавляет человеческий фидбек, который скрашивает сухие данные.

Кстати, если хотите собрать что-то похожее на персонального ассистента, обратите внимание на статью «Собираем локального Jarvis за вечер: ваш первый персональный ИИ-ассистент». Там описана архитектура, которая позволит вашей сводке не просто лежать в PDF, а инициировать действия — например, ставить задачи в Todoist по итогам дня.

Еще один нюанс: если вы используете несколько AI-инструментов для кода (Cursor, Windsurf), их история тоже может быть источником. Как разрулить конфликты между ними в одном репозитории — читайте в статье «AI-инструменты дерутся за ваш код: как остановить войну Cursor и Windsurf в одном репозитории». Там хитрый трюк с .gitignore и правилами для каждого assist.

Полный конфиг файла .env

# ActivityWatch (локальный, ключ не нужен)
AW_HOST=http://localhost:5600

# RescueTime
RESCUETIME_API_KEY=your_key_here

# Google Calendar iCal URL (публичная ссылка)
ICAL_URL=https://calendar.google.com/calendar/ical/.../basic.ics

# GitHub Token (Personal Access Token)
GITHUB_TOKEN=ghp_...
GITHUB_USER=yourname

# Telegram
TELEGRAM_BOT_TOKEN=123456:ABC-DEF...
TELEGRAM_CHAT_ID=123456789

# Таймзона (смещение от UTC в часах)
TIMEZONE_OFFSET=3

# OpenRouter или любой LLM для комментария
OPENROUTER_API_KEY=sk-or-v1-...

Скрипт daily_summary.py целиком я не привожу, чтобы статья не стала километровой. Но его легко собрать из кусочков выше. Если нужна моя версия с обработкой ошибок, таймаутами и красивыми таблицами — пишите в комментариях, могу выложить.

Бонус: интеграция с onWatch

У меня есть еще один инструмент — onWatch, Go-бинарник, который следит за квотами AI-провайдеров (Anthropic, Synthetic, Z.ai) и присылает уведомления, когда лимит исчерпан. Я добавил его данные в сводку дня, чтобы видеть, сколько токенов я потратил на ассистентов. Подробнее — в статье «onWatch: Go-бинарник, который следит за квотами Anthropic, Synthetic и Z.ai, пока вы спите».

Туда же можно засунуть и данные из Context7 — если вы используете MCP для доступа к документации, запишите, к каким страницам обращались. Это даст контекст: «Весь день читал документацию по новому API». Статья «Context7 MCP: как подключить к Claude для работы с актуальной документацией (пошаговый гайд)» поможет интегрировать этот источник.

В итоге за месяц у вас накопится база данных о собственной работе. Вы сможете делать аналитику: в какие дни вы максимально продуктивны, сколько времени уходит на встречи, какие приложения едят ваше время. И главное — перестанете врать себе про «я работал весь день».

А теперь — давайте перейдем к полному конфигурационному файлу, который я обещал.

Конфигурация скрипта (config.yaml)

# config.yaml
calendar:
  ical_url: "${ICAL_URL}"
  max_events: 10

activity_watch:
  host: "${AW_HOST}"
  bucket: "aw-watcher-window"
  timezone_offset: ${TIMEZONE_OFFSET}

rescuetime:
  api_key: "${RESCUETIME_API_KEY}"
  enable: true

github:
  token: "${GITHUB_TOKEN}"
  user: "${GITHUB_USER}"
  repos: ["my-repo", "work-repo"]

telegram:
  bot_token: "${TELEGRAM_BOT_TOKEN}"
  chat_id: "${TELEGRAM_CHAT_ID}"

output:
  format: "pdf"  # или "markdown"
  directory: "./reports"

Скрипт читает этот YAML, подставляет переменные окружения и генерирует отчет. Никаких жестко закодированных путей. Если хотите адаптировать под себя — просто меняйте YAML.

На этом все. Надеюсь, мой опыт поможет вам перестать гадать, что вы сделали за день. Если остались вопросы — пишите. Я отвечаю даже на глупые.

Подписаться на канал