
Привет Хабр!
Пару дней назад я опубликовал статью про ХрюХрюКар - телегам-бот для борьбы со стоянкой автомобилей на зелёных зонах. Проект с открытым исходным кодом.
За два дня ко мне обратилось несколько сторонников с просьбой добавить их города. Но вот незадача: у меня была возможность через админ-панель Django править данные в базе, но об этом кеш сервера не узнает (основной бекэнд на Go). В результате приходилось добавлять данные и перезагружать контейнеры с go-бекэндом вручную.
Основные серверы ХХК уже имели сторы, которые получают и обрабатывают апдейты, прилетающие через redis.
По сути, оставалось внести правки в часть django-бэкенда, чтобы обрабатывать сигналы pre_save
и pre_delete
, сериализовать данные и отправлять их в нужный канал редиса.
Решил поручить эту задачу Codex CLI, которую вчера OpenAI представили нам с вами. Хотелось посмотреть насколько этот инструмент будет полезен в среднего размера проектах с развитой структурой, средних размеров кодовой базой и широким стеком технологий.
Если у вас совсем нет времени на просмотр всего процесса, то вот что я получил от Codex CLI примерно за 22 минуты*, пару промптов средней длины, один промпт с трейсбеком из консоли и 1.17$.
*Примечание: работа выполнялась на ПК, имеющем слабый канал связи (скорость 5-10 Мбит/сек.)
Доработка кода на Python/Django
После установки и настройки Codex CLI, я перешел в корневую директорию ХХК и выполнил в консоли команду: codex "<промпт>"
и начал ждать.
Вот какой промпт я использовал:
У меня на бекэнде в Go есть сторы в папке go_backend/internal/store/redis_broker которые подписаны через редис на каналы go_backend/internal/store/channels.go. Через эти каналы сторы получают инфу об апдейтах go_backend/internal/store/update_messages.go. Сделай мне в бэкенде Django для моделей, которые в папке django_backend/core/models, набор простых сериализаторов (для преобразования экземпляра модели в простой JSON со всеми полями), при этом название и тип данных полей смотри в моделях в папке go_backend/internal/models. Сериализаторы положи в папку django_backend/core/serializers. Затем в папке django_backend/core/signals сделай обработчики сигналов pre_save и pre_delete для всех моделей, в которых надо формировать сообщения об апдейтах и засылать их в нужный канал редиса.
Вот процесс работы утилиты (ссылка на Youtube):
Codex CLI начал выполнять различные консольные команды, анализировать вывод и принимать дальнейшие решения. При стандартных настройках, все изменения требуют одобрения, однако можно запустить Codex CLI в полностью автоматическом режиме.
В результате первой итерации работы я получил вот этот коммит. Из положительных моментов: Codex CLI заметил что модели в Go-шной части проекта имеют теги для сериализации в JSON, которые отличаются от названия поля в модели Django. Это моя ошибка, но утилита сделала сериализатор с ее учетом.
Код по результату оказался рабочий и выполняющий мою задачу, но сервер Django не завёлся, а в консоли я увидел ошибку:
django_backend | Traceback (most recent call last):
django_backend | File "/backend/core/apps.py", line 10, in ready
django_backend | import core.signals # noqa
django_backend | ^^^^^^^^^^^^^^^^^^^
django_backend | File "/backend/core/signals/__init__.py", line 3, in <module>
django_backend | from .redis_signals import *
django_backend | File "/backend/core/signals/redis_signals.py", line 4, in <module>
django_backend | import redis
django_backend | ModuleNotFoundError: No module named 'redis'
Для чистоты эксперимента я решил сам не исправлять ситуацию, а просто скинуть этот трейсбек в Codex CLI. Вот результат (ссылка на Youtube):
Codex CLI предложил добавить в зависимости redis версии 4.7.0
. Я все-же проверил pypi
и взял последнюю версию 5.2.1
.
После пересборки контейнера сервер Django
завелся и все работало нормально. Однако мне было интересно проверить как будет происходить правка кода в той части проекта, которая написана у меня на Go
.
Доработка кода на Go
Я запустил codex
со следующим промптом:
пройди по всем сторам кеша в папке go_backend/internal/store/cache и везде в методе subscribeUpdates при получении апдейта перед блокировкой мьютекса выводи через s.log.Debug ... само сообщение апдейта, чтобы я видел что приходит через редис
Вот процесс работы утилиты (ссылка на Youtube):
В результате я получил то, что хотел, правда утилита немного мне поломала отступы. Линтер поправил все отступы при сохранении и я получил вот этот коммит.
Далее проверил что все работает:
Что по расходам?
Работала модель o4-mini
, потратил я 1,363,957 токенов, что стоило 1,17$:

Сейчас дашборд в OpenAI позволяет сохранять и смотреть всю историю запросов к API, и вот какого вида записи там:

Если провалиться в любую строку, то в каждой из них в начале будет набор инструкций из Codex CLI, мои инструкции, которые я положил в ~/.codex/instructions.md
, сам промпт и результат работы - либо ответ, либо вызов функции. Думаю что расход можно сократить, немного ужав набор своих инструкций. У меня в ~/.codex/instructions.md
были следующие инструкции (копипаста из другой утилиты):
## Global Coding Style
- Preserve my existing code style exactly.
- Use single-line formatting even for long lines — do not wrap lines.
- Keep comments in English.
- Maintain existing comment style, indentation, and spacing.
- Always use `//` for inline comments in Go.
- Do not reorder imports unless explicitly asked.
## Code Practices
- Keep logging format consistent.
- Use mutexes where concurrency issues may occur — match existing usage patterns.
- Respect metrics and monitoring setup already in the codebase.
- Avoid introducing external libraries unless explicitly permitted.
## Output Rules
- Only output changed lines or code snippets — do not repeat unchanged code.
- Do not add explanations unless explicitly asked.
- Avoid adding TODOs or FIXMEs unless explicitly requested.
## Language Specific
### Go
#### SQL Style
- Use raw SQL queries.
- If using `database/sql`, use `?` placeholders (MySQL).
- If using `sqlx`, use `:named` placeholders and `sqlx.Named` where applicable.
- Stick to the existing project style — do not mix styles across projects.
#### General Go Rules
- Preserve code style, comment format, and log structure.
- Do not auto-format or refactor unless explicitly requested.
- Follow existing patterns for SQL declaration blocks, struct tags, etc.
### Python
- Use Django ORM and DRF conventions.
- Use `gettext_lazy as _` for translations.
- Use snake_case for variable and function names.
Вывод
Утилита отлично справилась с решением конкретной задачи в проекте с кодовой базой средних размеров и развитой структурой.
Для оптимизации расходов можно использовать более дешевые модели, либо более точный набор инструкций, чтобы избежать затрат на анализ содержимого тех директорий и файлов, которых не касается контекст текущей задачи.