Как я перенёс Codex в Telegram — и в итоге написал собственного ассистента для Mac
Всё началось с желания быстро отвечать Codex с телефона. В итоге у меня появился голосовой Telegram-ассистент с проектами, задачами, памятью, календарём, дневником, рассказами и вечерними отчётами.
Я фитнес-тренер и параллельно разрабатываю собственный цифровой продукт. Мой обычный рабочий день проходит не за столом. Я постоянно на ногах: веду тренировки, перемещаюсь по залу, отвечаю клиентам, показываю упражнения и между подходами успеваю подумать о продукте, тексте или новой функции.
Идея часто приходит в тот момент, когда до компьютера ещё несколько часов. Иногда нужно быстро поставить задачу. Иногда — получить короткий отчёт по работе. Иногда — ответить Codex, чтобы он не стоял и продолжил выполнение.
Каждый раз открывать ChatGPT, ждать подключения к Codex на моём Mac, выбирать нужный проект и восстанавливать контекст слишком долго. Пока всё это загрузится, свободная минута закончится, клиент вернётся к следующему подходу, а мысль потеряется.
Мне нужен был другой сценарий: достать телефон, отправить голосовое или короткую текстовую команду в Telegram и сразу вернуться к работе. Не смотреть на экран, не ждать завершения и не держать задачу в голове. Ассистент должен принять поручение, выполнить его на домашнем Mac и прислать результат, когда он будет готов.
Мне был нужен не ещё один чат
К тому моменту Codex уже закрывал почти все мои рабочие и личные задачи: разработку, работу с файлами, исследования, документацию, подготовку текстов, планирование и клиентские сценарии.
Можно было построить отдельную систему автоматизаций на n8n или разбираться с OpenClaw. Эти инструменты, вероятно, полезны для сложных фиксированных процессов и большого числа интеграций - я до них так и не дошел. Но мне не хотелось создавать ещё один центр управления, изучать его логику, собирать отдельные сценарии и потом всё это обслуживать.
Основная работа уже происходила внутри Codex. Мне требовалась не новая платформа, а быстрый мобильный вход в существующую систему.
Мой Mac работает круглосуточно. Поэтому архитектура напрашивалась сама: Telegram принимает сообщения, локальный бот на Mac передаёт их в Codex, а результат возвращается в тот же чат.
Главное преимущество оказалось не в удалённом доступе как таковом, а в асинхронности. Я могу написать: «Задача — проверить ошибки production», убрать телефон и проводить следующую тренировку. Если Codex попросит разрешение, уточнение или выбор варианта, вопрос придёт в Telegram. Если всё понятно, результат появится там же без моего участия.
Сначала я решил не писать всё с нуля
Первым делом я посмотрел, какие мосты между Telegram и Codex уже существуют. Нашёл несколько open-source-проектов, которые умели создавать сессии, выбирать рабочую папку, показывать выполнение команд и передавать тред обратно на компьютер.
Это был правильный способ быстро проверить гипотезу. Уже в первый день стало понятно, что сам формат мне подходит: управлять Codex из Telegram действительно удобно.
Но как только я начал пользоваться ботом не для демонстрации, а в течение реального рабочего дня, появились десятки мелких проблем. Именно они постепенно превратили небольшой коннектор в отдельный продукт.
Реальный интерфейс проверяется раздражением
Первый список сессий технически работал, но пользоваться им было неудобно.
Наверху оказывались старые треды. Названия обрезались так, что разные сессии выглядели одинаково. В списке проектов появлялись временные и служебные директории, а одна рабочая область могла отображаться несколько раз.
Команда существовала, но задачу пользователя не решала. Это хороший пример разницы между функцией и продуктом.
Мы изменили сортировку по последней активности, скрыли временные папки, объединили одинаковые проекты и добавили понятные названия вместо путей на диске. Так в интерфейсе появились разделы «ТРЕНЕР», «КЛИЕНТЫ», «ДЕНЬГИ» и «В СВОЁМ ТЕЛЕ».
Это не демонстрационные примеры. Так действительно разделены мои рабочие контексты: тренерская практика, клиенты, финансы и цифровой продукт.
Частые действия переехали в постоянную клавиатуру Telegram. Теперь не нужно помнить команды и искать нужную сессию по техническому имени. Я сразу вижу область работы и могу продолжить с того места, где остановился.
Один тред — два устройства
Отдельный вопрос возник с продолжением работы на компьютере. Что делать, если задача началась в Telegram, а через час я сел за Mac?
Одновременно управлять одним активным ходом из двух интерфейсов опасно: легко отправить противоречивые ответы или потерять состояние. Поэтому я выбрал модель передачи управления.
В Telegram можно открыть существующий тред, продолжить его, а затем передать на Mac. Бот активирует Codex и подготавливает возобновление того же треда. История, рабочая директория и контекст сохраняются.
В обратную сторону всё работает так же: тред, созданный на компьютере, появляется среди последних сессий Telegram.
Отдельная облачная история чатов не понадобилась. Источником истины остался локальный Codex, а Telegram стал ещё одним интерфейсом к нему.
Бот не должен закрываться вместе с Codex
Первая версия бота жила рядом с текущей сессией разработки. После закрытия или перезапуска Codex мог исчезнуть и Telegram-бот.
Для эксперимента это терпимо. Для ассистента, которому отправляешь задачу между тренировками, — нет. Если я уже убрал телефон, поручение не должно пропасть из-за закрытого окна на Mac.
Я вынес процесс в пользовательский macOS LaunchAgent. Теперь бот запускается при входе в систему, работает независимо от Codex Desktop, автоматически перезапускается после сбоя и не требует открывать входящий порт.
После этого Telegram впервые стал ощущаться не как пульт для демонстрации, а как постоянный рабочий интерфейс.
Голосовые оказались отдельным продуктом внутри продукта
Для человека, который почти весь день двигается, голос — самый естественный способ поставить задачу. Печатать длинное сообщение одной рукой в зале неудобно. Записать двадцать секунд аудио можно по дороге от одного тренажёра к другому.
Сначала я хотел просто пересылать голосовое и получать короткое содержание, аккуратную расшифровку, смысловые абзацы, важные решения и метаданные отправителя.
Первая реализация провалила проверку на реальном сообщении. Расшифровка получилась длиннее оригинала, обращение распозналось неправильно, а неформальная речь неожиданно стала официальной. Текст выглядел красиво, но уже не соответствовал записи.
Это был важный урок: хорошее оформление не компенсирует ошибочную транскрипцию.
Я перешёл на локальный MLX Whisper с моделью whisper-large-v3-turbo. Аудио распознаётся на Mac, хранится только во временной папке и удаляется после обработки. Обычное голосовое не создаёт новый проектный тред и не меняет текущую сессию Codex.
Отдельный форматтер сохраняет смысл исходной речи, разбивает текст на абзацы и тезисы, исправляет пунктуацию и выделяет важные фрагменты. Telegram получает уже читаемый результат, а не набор служебных символов разметки.
Из расшифровки выросли дневник и рассказы
После обычных голосовых захотелось использовать тот же поток для личного дневника и цикла рассказов.
Теперь одна и та же логика работает и для голоса, и для текста. Сообщение начинается с простой метки: «Дневник», «Заметки», «Рассказ», «Календарь», «Задача», «Напоминание», «Идея» или «Запомни». Всё, что идёт после первого слова, бот направляет в нужный сценарий.
Например, я могу сказать: «Дневник. Сегодня понял, что слишком долго откладывал публикацию». Whisper расшифрует запись, Codex исправит орфографию и пунктуацию, уберёт повторы, разобьёт текст на естественные абзацы и аккуратно выделит важные мысли.
Готовая запись добавится в Apple Notes. Для дневника используется одна заметка на месяц, внутри которой записи сгруппированы по датам и времени. Параллельно сохраняется читаемая Markdown-копия и отдельная исходная расшифровка.
Если отправить только слово «Дневник» или «Заметки», бот покажет всё, что было записано за текущий день, и приложит тот же текст отдельным файлом.
Для рассказов можно выбрать название цикла. Новая запись получает контекст конца предыдущего черновика, поэтому голосовые фрагменты превращаются не в разрозненные заметки, а в последовательный текст.
Календарь тоже должен понимать нормальную речь
В движении я не хочу подстраиваться под строгий синтаксис. Команда «Календарь в четверг в 19:00 концерт» должна работать так же предсказуемо, как заполненная вручную форма.
Сначала запрос разбирают локальные правила. Они быстрые и хорошо обрабатывают знакомые конструкции. Если дата или время сформулированы необычно, бот делает отдельный безопасный запрос к Codex и просит вернуть только строго проверяемую структуру.
Даже после этого событие не создаётся автоматически. Бот показывает название, дату и время и ждёт подтверждения. Если результат неоднозначен, он просит уточнить формулировку.
Такой каскад оказался полезнее попытки сделать один огромный набор регулярных выражений или, наоборот, полностью доверить изменение календаря языковой модели.
Почта показала, насколько важна явная маршрутизация
Однажды я спросил бота: «Последнее входящее письмо?» — и увидел, что он собирается проверять Gmail. Возник закономерный вопрос: зачем тогда мы подключали Apple Mail?
В итоге я разделил ответственность. Gmail используется для поиска, чтения и краткого содержания писем через подключённый источник Codex. Apple Mail создаёт видимый черновик на Mac. Отправка, удаление и архивирование не выполняются без отдельного подтверждения.
Похожее правило действует в других интеграциях. Читать и изменять — разные уровни риска. Посмотреть календарь можно сразу, а создать событие — только после подтверждения. Фоновая задача не может сама разрешить опасную команду.
Чем больше возможностей появлялось, тем важнее становилось заранее определять ожидаемое поведение, а не просто давать модели доступ к очередному инструменту.
Почему я отказался от первоначальной основы
В какой-то момент стало ясно, что мы меняем уже не внешний вид готового бота, а почти все ключевые слои.
Появились задачи, очередь фоновых запусков, напоминания, долгосрочная память, поиск, ежедневные отчёты, голосовой редактор, Apple Notes, локальные интеграции macOS и другой способ общения с Codex.
Первоначальный SDK также не давал всех событий, которые нужны полноценному клиенту: управления активным ходом, разных типов подтверждений и полного контроля над тредами. Поэтому транспорт был переведён напрямую на codex app-server по JSON-RPC через стандартный ввод и вывод.
Продолжать тянуть первоначальный проект как основу стало бессмысленно. Но просто удалить чужой copyright из сильно изменённого репозитория было бы неправильно.
Я выбрал более трудоёмкий, зато чистый вариант: создал новый проект и переписал реализацию с нуля по функциональной спецификации, не копируя исходные файлы, тесты и историю Git.
Новый проект получил собственный транспорт к Codex, модель тредов и активных ходов, Telegram-интерфейс, SQLite-схему, планировщик, голосовой поток, интеграции macOS, тесты, мигратор данных и LaunchAgent.
Перед публикацией я отдельно проверил код на токены, API-ключи, личные пути и чужую лицензионную информацию. Только после этого новый процесс заменил старый, а репозиторий был опубликован под MIT.
Что получилось сейчас
Сегодня ассистент умеет:
— показывать, открывать и продолжать существующие Codex-треды;
— создавать общий чат или отдельную проектную сессию;
— принимать уточнения во время активной работы и прерывать выполнение;
— показывать в Telegram запросы на разрешения и варианты ответа;
— передавать тред между Telegram и Mac без потери рабочей директории;
— создавать задачи, хранить инбокс и последовательно запускать поручения в фоновой очереди;
— сохранять долгосрочную память по проектам и искать по задачам, сообщениям, инбоксу и тредам;
— принимать текстовые и голосовые команды без включения отдельных режимов;
— вести дневник и циклы рассказов с публикацией в Apple Notes и локальными резервными копиями;
— работать с Gmail, Apple Mail и Calendar с явным разделением чтения и изменений;
— присылать утренние уведомления и межпроектный вечерний итог;
— показывать в вечернем отчёте первую и последнюю команду за день, общее рабочее окно, расчётное активное время и длинные перерывы;
— форматировать ответы для Telegram и безопасно возвращаться к обычному тексту, если разметка не принимается.
Вечерний отчёт особенно хорошо соответствует моему рабочему ритму. В 21:00 бот собирает, чем мы занимались по всем проектам, что завершили, какие решения приняли, где остались блокеры и что стоит перенести на завтра.
Он также показывает, во сколько я впервые обратился к ассистенту и во сколько отправил последнюю команду. Разрывы между обращениями дольше часа считаются простоями и вычитаются из расчётного активного времени. Это не система учёта рабочего времени и не наблюдение за компьютером, а понятная оценка по фактическому взаимодействию с помощником.
Как это устроено
Telegram получает сообщения через long polling. На Mac работает Node.js-бот, который общается с codex app-server через стандартный ввод и вывод. Состояние задач, памяти, напоминаний и настроек хранится в SQLite. Голос распознаёт MLX Whisper. Локальные действия выполняются через приложения macOS.
Входящего сервера нет. Доступ ограничен разрешёнными Telegram user ID. Пароли, токены, локальная база, логи и модели не попадают в Git.
После последнего обновления проект проходит 47 автоматических тестов. Production-версия работает через LaunchAgent и автоматически поднимается после перезапуска процесса.
Что я понял за этот эксперимент
Первое: не всегда нужна отдельная платформа автоматизаций. Если основная работа уже происходит внутри универсального агента, иногда достаточно сделать хороший интерфейс постановки задач, уведомлений и подтверждений.
Второе: начинать с готового проекта было правильно. Он позволил за несколько часов проверить, нужен ли мне Telegram как рабочий интерфейс. Переписывать с нуля имело смысл только после того, как гипотеза подтвердилась и требования стали понятны.
Третье: собственное ежедневное использование важнее длинного списка функций. Проблемы с сортировкой, названиями проектов, расшифровкой и маршрутизацией невозможно почувствовать по README. Они становятся очевидны, когда пытаешься дать поручение за тридцать секунд между подходами клиента.
Четвёртое: голос — это не ещё один тип файла. Для него важны точность, стиль речи, длина результата, метаданные, дальнейшее хранение и понятный сценарий использования.
Пятое: агенту нужны границы. Прочитать письмо и отправить письмо — разные действия. Посмотреть календарь и создать событие — тоже. Чем больше интеграций, тем важнее явно разделять чтение, подготовку и изменение внешнего состояния.
И последнее: хороший ассистент экономит не только время выполнения задачи. Он снижает цену переключения внимания. Для меня это главный результат проекта. Я могу за полминуты выгрузить мысль или поручение, убрать телефон и продолжить тренировку. Работа не останавливается, а мне не нужно держать её в голове.
Репозиторий
Проект опубликован под лицензией MIT.
Сейчас это в первую очередь мой личный рабочий инструмент для Mac, а не продукт, который устанавливается одной кнопкой. Понадобятся локальный Codex, Telegram-бот, Node.js и небольшая настройка. Голосовая расшифровка рассчитана на Apple Silicon и MLX Whisper.
Если вам близок сценарий «Mac работает дома, а Codex нужен с телефона», буду рад обратной связи, issues и идеям. Особенно интересно, какие действия вы бы вынесли в Telegram, а какие принципиально оставили бы только на компьютере.