Вернувшись из отпуска, завершил переезд JS->TS (ушло где то 35 PRs на это)
Я начал улучшать UI (это моё любимое), понравилось как оно стало улучшаться и тут уже разыгрался азарт! Решил, что нужно придумать название.
Gristmill – «meeting notes, milled fine»
Главная идея: артефакты митинга принадлежат вам и вы можете обрабатывать их любыми инструментами.
Помните мой фейл в авто, когда отвалился мобильный хотспот и Granola потеряла 20 минут речи собеседника?
В Gristmill архитектура построена ровно наоборот:
1. Запись локально. Микрофон и системное аудио пишутся в два раздельных трека (Ogg/Opus) нативно через Swift/FFmpeg. Едешь в лифте, переключаешь VPN, падает Wi-Fi — пофиг, звук пишется прямо на диск и никуда не пропадет.
2. Record then process. Никакого ненадежного стриминга на лету. После созвона нажал «Stop» — готовый звук уходит на транскрибацию и диаризацию.
3. Транскрипт и саммари — это всего лишь артефакты. Не понравился результат или модель затупила? Нажал одну кнопку и пересобрал транскрипт другой моделью (хоть Gemini, хоть Deepgram, ElevenLabs, OpenAI или локальным Whisper/Llama/Sherpa). А исходное аудио всегда у тебя под рукой. Я пока что пользуюсь Deepgram, мне хватает.
Ещё по фичам:
- Speaker labels
Это фича, которая соотносит распарсенных спикеров в аудиозаписи с участниками созвона.
Как это сделать? Расковырять Granola!
Именно расковырять, а не сделать реверс-инжениринг! Это важно! Иначе, можно словить письмо счастья от OpenAI))
Я сначала думал, что такие крутые чуваки как Granola парсят участников как то по умному и хитром, но оказалось, что у них есть просто парсилка интерфейсов, и при этом даже не любых, а только Zoom (работает через MacOS Accessibility API), Google Meet (работает через Google Chrome extension) и Microsoft Teams (слава богу мне это чудо инженерной мысли не нужно, так что я с ним не разбирался).
Короче, расковырял это и стащил себе. Добавил ещё поддержку Телемоста, так же через такой же Chrome Extension.
Теперь, приложение должно понимать, кто в какой момент какую фразу сказал.
- Чат
Для чата я решил, что хочу использовать имеющуюся охапку подписок – opencode go, clinepass, z.ai, codex.
Но как сделать это проще? Выход – bb
Я пользуюсь им уже около месяца, оч нравится.
Добавил в Gristmill поддержку bb очень быстро и теперь есть возможность использовать любой harness, в том числе и даже claude code!
- Внешний доступ
Для доступа агентов к материалам созвона я решил, что сделаю cli + skill и его будут использовать как внутренние агенты (через bb), так и любые внешние, получилось очень удобно!
Ещё топовая фича - нескучные
По самым крутым фичам пока что всё, но вот что ещё агенты делали:
- Strict TypeScript + Zod везде
Полностью убрали нетипизированный IPC-ад между процессами Electron. Все вызовы строго валидируются через контракты.
- Переезд на Oxlint / Oxfmt
Линтинг и форматирование теперь летают за миллисекунды, агенты не спотыкаются о кривые конфиги. Тут кстати тоже очень много времени ушло - около 4 дней работы, 27 issues, +77k / -23k LOC. Но зато теперь у меня есть:
- архитектурные границы в каждом из модулей (бэк, UI, chrome extension и т. д.)
- дефолтные no any, as unknown as T и т. д.
- кастомные правила под проект
- и ещё куча других правил, которые я стащил откуда-то
Сегодня я делаю репозиторий публичным.
Это мой первый опыт опенсорса, так что принимаю issues и PRs.
Лайк, репост,