Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions ARTICLE_LINKEDIN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Скільки насправді часу пішло на Xsistant — трекер активності під Ubuntu

Пару днів тому закрив невеликий проєкт — **Xsistant**, agent-трекер для Ubuntu/GNOME, який пише активність користувача (клавіатура, миша, фокус вікна) у PostgreSQL і сам же прив'язує її до проєкту. Ділюся чесною хронологією: скільки зайняло не «за календарем», а фактично.

Репозиторій (публічний): https://github.com/overthelex/aisisstant

---

## Метрика часу: за пушами в master та релізами

Я працюю trunk-based — комічу одразу в `master`, тому **PR для таймкіпінгу немає**. Зате кожен пуш у `master` тригерить CI і викочує реліз на self-hosted runner. Релізи — найчесніший таймстемп «момент, коли шматок коду реально поїхав у прод».

Дані з `gh release list` (час EEST):

📦 16 Apr, 13:29 · v2026.04.16
Python-агент, колектори, схема БД

📦 16 Apr, 13:37 · v2026.04.16.1
CI/CD pipeline + CalVer-версіонування

📦 16 Apr, 13:43 · v2026.04.16.2
switchamba fallback для window tracking

📦 16 Apr, 13:47 · v2026.04.16.3
AT-SPI + нормалізація заголовків

📦 16 Apr, 14:26 · v2026.04.16.4
нормалізація Thunderbird/LibreOffice/VLC/Telegram

📦 16 Apr, 15:33 · v2026.04.16.5
GTK4/Adwaita setup wizard + .deb packaging

📦 17 Apr, 00:24 · v2026.04.17
Xsistant rebrand, брендинг, логотип

📦 17 Apr, 11:36 · v2026.04.17.1
GNOME top-bar indicator + фікс Postgres-hang

📦 17 Apr, 22:22 · v2026.04.17.2
project attribution + stats panel + pause/quit

---

## Чесний підрахунок «робочого часу»

Якщо подивитися на інтервали між релізами і викинути «паузи на поїсти/поспати/зайнятися іншим»:

- **16 Apr, 13:16 → 15:33** — основний ривок: від порожньої папки до робочого `.deb` з GUI-візардом. **≈ 2 год 15 хв.**
- **17 Apr, 00:24** — брендинг і rename у Xsistant. **≈ 30 хв** (логотип уже був готовий, треба було лише прошити).
- **17 Apr, 11:36** — top-bar індикатор у GNOME Shell + фікс гонки з Postgres при завантаженні системи. **≈ 45 хв.**
- **17 Apr, 22:19** — project attribution через cwd фокусного вікна + stats-панель. **≈ 1 год.**

**Разом чистого часу: ≈ 4 год 30 хв.**
Календарний строк — півтора дня (33 години від першого коміту до останнього).

Так, це відчувається швидко. Але все, що нижче — це не диво, а **нудьга**: звичайна декомпозиція + доступні інструменти.

---

## Що увійшло в ці 4.5 години

### 1. Сам трекер (Ubuntu Linux)

Python-агент, асинхронний, на `asyncio`. Три колектори:

- **Клавіатура/миша** — напряму з `/dev/input/event*` через `evdev`. Чесні натискання без прив'язки до конкретного вікна/застосунку.
- **Вікно у фокусі** — два шляхи, за пріоритетом: AT-SPI (через `pydbus`) → fallback на власну маленьку утиліту **switchamba** (теж мій deb-пакет, через `xdotool`/`wmctrl`).
- **Мікрофон** — D-Bus події PulseAudio/PipeWire.

Агент живе як `systemd --user` service. Встановлюється одним install-скриптом або `.deb`. БД — PostgreSQL у `docker compose`, піднімається автоматично.

### 2. GitHub Actions (self-hosted runner)

Workflow з трьох jobs: **test → deploy → release**.

- Тести (`pytest`) ганяються і на PR, і на push.
- `deploy` — лише на push у `master`: оновлює systemd-юніт, копіює GNOME-розширення, рестартить сервіс і робить health check.
- `release` — **автоматичний CalVer** (`YYYY.MM.DD`, з суфіксом `.N` при кількох релізах на день). На льоту підміняє версії у `pyproject.toml`, `aisisstant-setup`, `debian/changelog`, збирає `.deb` через `dpkg-buildpackage` і публікує GitHub Release з прикріпленим артефактом.

Чому self-hosted: агенту потрібні `$DBUS_SESSION_BUS_ADDRESS` і живий user-session, щоб дотягнутися до `systemctl --user`. GitHub-hosted runner цього не дасть за визначенням.

### 3. Коректне перемикання «активність → проєкт»

Це був найцікавіший шматок (і саме на нього пішла остання година).

**Проблема:** десять IDE, терміналів і браузерних вкладок у різних проєктів виглядають у заголовку вікна однаково розмито. Парсити title — крихко.

**Рішення:** коли фокус іде на вікно, колектор знаходить PID власника вікна, читає `/proc/<pid>/cwd` (і по всіх child-процесах, якщо це термінал із запущеним shell/IDE), порівнює з коренями відомих проєктів і проставляє `project_id` прямо у `activity_scores`. Якщо cwd за межами проєктних директорій — пишеться `null`, не ламаємо звіти шумом.

Плюс невеликий «дедуп» за заголовками: різні таби одного Firefox не дроблять сесії, VS Code вікна з однаковим workspace-коренем вважаються одним контекстом.

Підсумок — `aisisstant-report` і stats-панель у top-bar показують чесні хвилини на проєкт, без ручної розмітки.

---

## Що я забираю з цього експерименту

1. **Trunk-based + CalVer + self-hosted runner** — достатня зв'язка для pet-project під одного користувача. PR-процес тут був би бюрократією без профіту.
2. **GNOME Shell extension + D-Bus** — недооцінений спосіб інтегруватися в desktop без демона на X11-хаках. Індикатор у top-bar написаний за один присід.
3. **`.deb` через `dpkg-buildpackage`** простіше, ніж здається. `debian/` з 10 файлів + один `rules` на 3 рядки — і у тебе нативний пакет, який ставиться через `apt install ./file.deb` разом із залежностями.
4. **«cwd фокусного процесу»** — найнадійніший сигнал належності до проєкту на Linux. Набагато точніше, ніж title-парсинг, і працює для будь-якого IDE.

---

## Що далі: інтеграція з Plane

Наступний крок — **автоматична прив'язка активності до задач у Plane**. Ідея проста: розробник не має сидіти із секундоміром і згадувати в кінці дня, скільки пішло на тикет. Це одна з найдратівливіших частин тайм-трекінгу в будь-якій команді.

Як це працюватиме:

- Xsistant уже знає, у якому **проєкті** ти зараз працюєш (через cwd фокусного вікна).
- Наступний шар — прив'язка до **активної задачі**: або через вибір у top-bar індикаторі, або автоматично — за іменем гілки (`feature/PROJ-123-...` → тикет `PROJ-123`), або за заголовком вікна IDE з номером задачі.
- Агент агрегує хвилини активної роботи (клавіатура/миша/фокус вікна проєкту) і **сам пише worklog у Plane** через їхній API.
- Розробник нічого не заповнює вручну. У кінці спринта — чесні цифри, без «ну накину години зо три, начебто стільки було».

Мета — прибрати психологічний тягар тайм-трекінгу. Трекер уже збирає всі потрібні сигнали; залишилося замкнути петлю на таск-трекер.

---

**TL;DR:** від `git init` до робочого `.deb` з CI, GNOME-індикатором і project attribution — **~4.5 години чистого часу** за півтора дня календаря. Далі — інтеграція з Plane, щоб розробники не заповнювали worklog руками. Код: https://github.com/overthelex/aisisstant
Loading