Від ідеї до сайту за вечір: як я прибрав себе з інтерв'ю
Я провів інтерв'ю вручну — копіював повідомлення між AI-агентом і учасником, як живий посередник. Після цього написав нотатку з ідеєю прибрати себе з ланцюжка. За один вечір нотатка стала живою платформою.
Я був пляшковим горлечком
Перше інтерв'ю за форматом "AI питає — людина відповідає" я провів вручну.
Схема виглядала так: Сюзанна (мій AI-агент) генерує питання → я копіюю його в Telegram → Ігор Степанушко відповідає → я копіюю відповідь Сюзанні → вона думає, пише внутрішній коментар → генерує наступне питання. І так по колу, 10 разів.
Все спрацювало. Ігор — «свідок аналогової епохи»: дитинство біля Чорнобильської «Дуги», книги замість інтернету, роздуми про межі людського мислення й довіру до ШІ — стаття вийшла. Але на 10 питань пішло три дні. Я був посередником. Якщо Ігор відповів пізно ввечері — я дізнавався вранці. Якщо я відволікся — інтерв'ю стояло. Все крутилось навколо моєї доступності.
Ідея осіла і лежала кілька тижнів. Одного вечора в кінці червня я сів, написав нотатку з однією думкою: що якщо прибрати мене з цього ланцюжка? — і не закрив ноутбук до 2 ночі.
Що я хотів збудувати
Ідея була простою: учасник отримує посилання, відкриває сторінку, бачить питання — відповідає коли зручно. AI думає, формулює наступне. Без мене посередині.
Але це не просто про Ігоря. Поки я писав нотатку, зрозумів ширший сценарій.
Я давно хочу записати спогади батьків — про дитинство, про 90-ті, про людей яких я вже не знаю особисто. Профілі є в сімейному дереві, але там дати і факти, не живі деталі. Є друзі про яких я, чесно кажучи, знаю мало — хочу почути їх думки і поки є час. Є теми де я сам хочу зупинитись і подумати вголос — не написати есе, а відповісти на питання. Щотижня можна дивитись які є прогалини у власній біографії і запускати коротке автоінтерв'ю з телефона. Другий мозок від цього тільки виграє.
Але все це вимагало аби я не був у центрі процесу.
З цього виросло кілька конкретних вимог до системи — і кожна прямо випливала з того що набридло в ручному режимі.
Найважливіша — асинхронність: учасник відповідає коли зручно йому, хоч о 23:00, хоч через три дні, а AI сам відновлює контекст незалежно від того скільки часу минуло між питаннями. Без цього вся ідея просто повторює той самий ланцюжок з копіпастом, тільки з іншим виконавцем.
Друга — нульова участь модератора, бо якщо я знову стану вузьким горлечком, сенс зникає. Я створюю інтерв'ю однією командою: тема, ціль, ім'я учасника — і далі система сама, а я тільки отримую Telegram-сповіщення коли інтерв'ю почалось і коли завершилось.
Третя — vault як вихід, не другорядна деталь, а половина сенсу: кожне питання і відповідь одразу лягають markdown-файлом в Obsidian, і після інтерв'ю я відкриваю нотатку з уже готовим матеріалом, а не з розшифровкою яку ще треба зробити.
І четверта, дрібніша, але без неї десять питань швидко стають замало — можливість продовжити: якщо хочеться ще, кнопка "+5 питань" без перезапуску всього інтерв'ю.
Найцікавіша частина: вступне "нульове" питання. Не технічне і не по темі — просте "розігріваюче" яке знімає напругу від стартового екрану. Щось типу "Що для тебе найважливіше коли ти згадуєш 1990-ті?" Відповідь на нього не рахується в основну серію, але задає контекст для всього що йде після.

Технічні рішення — і чому саме такі
Перше питання: стек. У мене вже є Agentia (https://agentia.lavrynovych.net/) — платформа для AI-агентів, побудована на TypeScript + Fastify v5 + SQLite. Логічно взяти той самий стек: знайомий, вже налаштований у vault, деплоїться тим самим Docker-compose.
Альтернатива — Python + FastAPI — відпала одразу. Не тому що гірше, а тому що ментальний перехід між двома стеками в рамках одного вечора — зайве тертя.
Чому SQLite, а не Postgres. Платформа живе на одному LXC-контейнері, трафік мінімальний, паралельних записів кілька на хвилину. SQLite з WAL-mode (PRAGMA journal_mode = WAL) справляється і не потребує окремого сервісу. Один Docker-контейнер, один volume.
Чому vanilla JS, а не React. Сторінка робить одну річ: показує питання, приймає відповідь, опитує сервер кожні 5 секунд. Це 150 рядків JavaScript. React тут — зайве ускладнення і зайвий час на налаштування. Polling реалізується через setInterval і fetch. Жодної залежності.
// Весь polling-механізм — 10 рядків
async function poll() {
const state = await fetchState(code);
if (state.processing) return; // ще думає — чекаємо
if (state.current_question) renderQuestion(state.current_question);
if (state.status === 'completed') showComplete(state);
}
setInterval(poll, 5000);Як AI генерує питання. Кожне питання — окремий виклик Anthropic API або OpenRouter (перемикається через env-змінну). Контекст: тема, ціль інтерв'ю, вся попередня розмова. AI пише два блоки: внутрішній коментар (що він почув, куди варто копати) і власне питання. Коментар — тільки для мене, в Obsidian ховається у %% ... %% блоки.
Vault sync після кожної відповіді. Не в кінці — після кожної мутації. Якщо сервер впаде посередині — втрачаю максимум одну відповідь, не все. Синхронізація не блокує HTTP-відповідь: виконується через setImmediate, помилка логується але не скасовує збереження.
Найважливіший момент, однак, стався під час тестування. Я побачив як агент пише свої внутрішні думки перед питанням — markdown-блок %% ...%% де він фіксує що почув і куди хоче копати. І тоді зрозумів: питання що виникають як продовження розмови, а не заплановані заздалегідь — відчуваються принципово інакше.
Уяви анкету для десяти людей про мене. Однакові питання для всіх. Деякі будуть не актуальні — бо хтось знає мене як друга, хтось як колегу, Віка — як чоловіка, хтось просто як хлопця що ганяє на джетті. У кожного різні спогади і різні ракурси. Адаптивні питання дозволяють кожному пройти свій маршрут. Це розмова тет-а-тет, яка відчувається натурально — але має кінцеву ціль.
Ось як це виглядає в реальному vault-файлі — фрагмент з тестового прогону платформи:
### Q4
> З огляду на ваш досвід, яку одну річ ви б змінили або додали до платформи?
Хотів би щоб коли я додаю ще 5 питань то прогрес-бар вгорі оновлювався
і показував ще й їх.
*Учасник швидко зорієнтувався в новій платформі і одразу запропонував
конкретне покращення щодо прогресу. Відчувається, що людина мислить
практично та цінує зворотний зв'язок в інтерфейсі.*
%%
КЛЮЧОВІ ТЕМИ: перше враження, роль ШІ-агента, потреба в динамічному
оновленні індикатора прогресу.
НЕРОЗКРИТО: що саме він очікував від платформи до початку, чи є досвід
роботи з іншими подібними сервісами.
%%Курсив — коментар AI одразу після відповіді, видимий тільки мені. Блок %% ... %% — те саме, але розгорнуте: що почув агент, які варіанти розглядав для наступного питання, чому обрав саме цей напрямок. В Obsidian це ховається автоматично, в Ghost — просто не потрапляє в публікацію.
Як це виглядає в браузері
Сторінка навмисно мінімальна.
Одна колонка, зверху вниз: контекстний блок з темою і ціллю інтерв'ю, вступне питання, далі кожне наступне питання з полем відповіді під ним. Знизу — "Відправити" і "Пропустити" (для вступного питання). Коли AI думає — спінер і текст "Агент формулює наступне питання".
Жодних акаунтів. Ніякої реєстрації. Код доступу зберігається в localStorage — Ігор відкриває посилання вдруге і одразу бачить де зупинився.
На головній — список активних інтерв'ю з іменами учасників і прогресом. Це для мене: відстежити хто де.
Після завершення — кнопка "Завантажити запис". Натиснувши, отримуєш markdown-файл з повним діалогом. Той самий файл який вже є у vault, але для учасника — як артефакт на пам'ять.


Зліва — головна сторінка зі списком інтерв'ю і прогресом кожного, справа — сторінка окремого інтерв'ю з питаннями і відповідями
MCP: створення інтерв'ю однією командою
Є ще один шар який не видно ззовні: MCP-сервер.
MCP (Model Context Protocol) — спосіб дати AI-агенту доступ до зовнішніх інструментів. Я написав stdio MCP-сервер для Herald (мій Claude Code CLI), і тепер створення інтерв'ю виглядає так:
interview_create({
participant: "Ігор Степанушко",
participant_link: "[[Ihor Stepanushko]]",
topic: "Телебачення 1990-2000-х",
goal: "зберегти спогади про аналогову епоху",
num_questions: 10
})Herald викликає цей інструмент, сервер генерує slug, access_code, запускає вступне питання — і через 3-5 секунд повертає посилання для учасника.
Чотири інструменти: interview_create, interview_list, interview_activate, interview_status. Цього вистачає, щоб вести весь цикл із CLI, не заходячи у браузер.
Також MCP використовує мій AI-агент Сюзанна.
Що пішло не так
Перша реальна сесія показала баг.
Я відповів на 10 питань, потім натиснув "+5 питань". Прогрес-бар показав 10/10 і не змінився. Одинадцяте питання з'явилось, я відповів — і інтерв'ю знову закрилось. Прогрес: 11/10. Потім 4/3. Щось ламалось при кожному extend.
Знайшов за 10 хвилин. Маршрут /extend передавав num_questions + 5 у AI-промпт — щоб агент знав скільки питань загалом. Але не зберігав це значення в базу даних. База лишалась зі старим числом. При наступній відповіді сервер рахував: answered(4) >= num_questions(3) → інтерв'ю завершене.
Рішення: окрема функція extend_interview() в DB-шарі яка атомарно оновлює num_questions і скидає vault_synced_at:
export function extend_interview(id: string, extra = 5): number {
db.prepare(
'UPDATE interviews SET num_questions = num_questions + ?, vault_synced_at = NULL, updated_at = ? WHERE id = ?'
).run(extra, Date.now(), id);
const row = db.prepare('SELECT num_questions FROM interviews WHERE id = ?').get(id);
return row.num_questions; // повертаємо новий total
}vault_synced_at = NULL — окремо важливо: скидає vault_ready, щоб UI не показував кнопку завантаження поки не завершено нову серію і не додано фінальну рефлексію.
Задеплоїла Сюзанна. Через 5 хвилин: "фікс спрацював".
Хто деплоїв платформу
Тут є нюанс який я хочу зафіксувати.
Claude Code написав увесь код. Але задеплоїв платформу він.
У мого vault є ще один агент — Сюзанна, AI-агент побудована на Hermes-платформі і налаштована на автономну роботу зі серверами. Вона має SSH-доступ до LXC 111, вміє запускати Docker, робити git pull. Їй я передав deploy.sh і технічну інструкцію.
Логи деплою прийшли в Telegram. Через кілька хвилин після команди:
✅ Health check passed: {"status":"ok","version":"1.0.0"}
📡 Interview Platform: https://interview.lavrynovych.netЦе не автоматизація заради автоматизації. У мене є сервер в Черкасах, Cloudflare tunnel і кілька LXC-контейнерів. Сюзанна знає цю інфраструктуру. Делегувати деплой їй — природньо. Я займаюсь кодом і архітектурою, вона займається операціями.
Те що ще попереду
Перша реальна сесія одразу показала куди рости.
Структуровані атрибути — з кожної відповіді витягувати структуровані факти: місто, рік, подія, емоції. Тоді можна робити запити типу "всі люди що згадували Харків 1960-х" або будувати географічну карту спогадів. Поки ідея в нотатках, але зрозуміло що потрібен окремий асинхронний AI-виклик після кожної відповіді і нова таблиця extracted_facts в БД.
Колективний мозок через Agentia — що якщо замість одного AI кілька обговорювали б між собою яке питання поставити наступним? Один агент фокусується на емоціях, інший — на фактах, третій — на суперечностях в розповіді. Модератор синтезує. Перший кандидат на таке інтерв'ю — знову Ігор: цікаво побачити що дасть розмова де кілька AI думають разом.
Публічний режим — зараз кожне інтерв'ю під конкретну людину. Але що якщо зробити шаблон без прив'язки до учасника: відкрите посилання або загальний ключ, учасник сам вводить ім'я і тему/ціль? Один шаблон, десятки учасників. Це буде масовий збір спогадів.
Що це змінює
Коли я прокинувся — побачив сповіщення в Telegram. Ігор завершив інтерв'ю. Це був справді радісний момент: він завершив без жодного нагадування з мого боку, і я знав що ми це зможемо обговорити.
Я відкрив vault вранці — там вже була нотатка з усіма 10 питаннями, відповідями і внутрішніми коментарями агента.
Але ранкове сповіщення — тільки перший шар.
Тепер я можу запросити батьків. Або запустити автоінтерв'ю собі на телефоні щоп'ятниці: подивитись які є прогалини у власній біографії і спитати себе про них. Не писати есе — просто відповідати на питання. Vault отримує живий матеріал замість порожніх полів у профілі.
Я так мало знаю про деяких друзів. Тут є шанс почути їх думки і розповіді — з мінімальним вкладенням часу з мого боку. Оточення різноманітне — і кожна розповідь, що потрапляє у vault робить загальну картину повнішою.
Тут є ще одна річ, яку я недооцінив, коли писав ту нотатку в кінці червня.
Спогади батьків не вічні. Є вікно — може п'ять, може десять років — коли ще можна почути живу розповідь: конкретні деталі, роки, люди, місця. Після — тільки загальні контури. Я давно хотів це зробити, але завжди "пізніше" — бо треба знайти час, бути присутнім, вести розмову самому. Тепер умови змінились: я надсилаю посилання, вони відповідають коли зручно, AI веде розмову і сам запитує деталі яких я б не згадав. Vault отримує живу нотатку замість порожнього поля у сімейному дереві.
Це не "зручніше". Це "стало можливим".
Але є один поворот, якого я не очікував.
Я побудував платформу, щоб слухати інших. Надіслав Ігорю посилання — він вже чув про систему, бо я розповідав йому про неї напередодні. AI вів розмову поки я спав, а вранці у vault мене чекала готова нотатка.
Виходить, я побудував систему, щоб слухати інших — а вона першою навчила слухати мене.
Код платформи — у відкритому репозиторії: github.com/vlavrynovych/interview-platform.
Питання про архітектуру або специфічні рішення пишіть в коментарях, або відкривайте гілку в репозиторії проекту.