Nova компилируется в C, имеет сборщик мусора и рантайм M:N: лёгкие задачи поверх потоков ОС, как горутины в Go. Это язык для бэкенда и серверных программ, похожий на Go и Rust, и его автор проектирует вместе с ИИ-агентами, в основном с Claude. Одиннадцать случаев, когда пришлось спорить о синтаксисе, он разобрал в отдельной статье.
Ключевая особенность Nova - эффекты. Функция прямо в сигнатуре объявляет, что делает с внешним миром: работает с сетью, часами, файлами, может завершиться ошибкой. Реализацию эффекта можно подменить в рантайме, например в тестах. Запись эффектов стала первым полем боя, и на ней хорошо видна разница между логикой агента и вкусом человека.
Роли распределены жёстко. Автор задаёт направление, оценивает, как строка читается, и принимает финальное решение. Claude предлагает варианты, обосновывает их и помнит уже принятое. Агент пишет и помнит, человек спорит и выбирает. Почти все конфликты растут из этого деления: то, что агент запомнил, он же и защищает.
Зачем вообще спорить с ИИ о синтаксисе
Делегировать проектирование языка агенту целиком не получается. Модель выдаёт варианты быстро, но выбор между ними упирается в критерий, который живёт не в тексте обоснования, а в голове того, кто будет читать код через год.
Кто что делает: роли человека и агента в проекте Nova
Автор держит видение языка и вкус: каким должен быть Nova, что в нём уместно, а что превратит его в чужой язык с другим именем. Он же говорит «нет», и делает это часто. Claude отвечает за перебор: предлагает варианты синтаксиса, подводит под них обоснования, помнит, что уже записано в спецификации.
Память агента объясняет его поведение. Агент устроен как модель плюс программная обвязка с памятью и инструментами, и именно накопленный контекст делает его из генератора вариантов защитником ранее записанного решения (разбор про обвязку и память агентов). Новый аргумент человека сталкивается не с пустой моделью, а с историей собственных предложений.
Правило автора: всегда дать агенту аргументированно изложить идею и принять её, если она хороша и согласуется с видением. Он отмечает, что почти каждый раз итог оказывался лучше того, что Claude защищал вначале. Спор нужен не для победы над моделью, а для проверки собственного решения на прочность.
Почему синтаксис - особенно неудобная задача для LLM
ИИ рассуждает логически: «символ свободен», «парсер однозначен», «согласовано с дженериками». Человек смотрит на строку и видит, как она читается с первого взгляда. Этого ИИ пока не умеет.
Логическая непротиворечивость и читаемость - разные критерии, и агент оптимизирует первый. Проверить, что символ нигде не занят, легко. Проверить, что !throws не читается как отрицание, можно только глазами и опытом чтения чужого кода.
Отсюда механика большинства из 11 споров: агент выдаёт локально корректное обоснование, автор отвечает фразой о том, как это выглядит на странице, и раунд закрывается. Спор идёт не о фактах, а о критерии оценки.
Спор №1: восклицательный знак для эффектов и почему он не выжил
В одной из ранних версий синтаксиса Claude предложил помечать эффекты восклицательным знаком:
fn save(u User) !throws io async -> ()
Обоснование было логичным: ! свободен, ни для чего важного не используется, похоже на Swift. Проверка на занятость символа пройдена, аналогия найдена, предложение готово к принятию.
Автор ответил одной фразой: «!throws выглядит как not». Claude согласился почти сразу. Эффекты стали обычными словами между ) и ->, без дополнительных маркеров:
fn save(u User) Throws Io Async -> ()
Потом язык менялся ещё. Throws переименовали в Fail, а Async убрали из системы типов: асинхронность стала делом рантайма M:N. Сигнатура сейчас может выглядеть так: Fs Fail[IoError]. Принцип сохранился: эффекты пишутся словами, сигнатура читается без расшифровки.
Вывод для читателя простой. Аргумент «символ свободен» отвечает на вопрос занятости символа, а не на вопрос читаемости. Одна фраза о том, как строка выглядит, обнулила логичное обоснование, потому что била в критерий, который агент не проверял.
Спор №2: массивы [T] и ловушка согласованности с дженериками
Сначала массивы в Nova писались как [T], в стиле Rust и Swift. Claude защищал запись двумя аргументами: согласовано с дженериками Option[T] и HashMap[K, V], парсер однозначен.
В этом обосновании смешаны два разных источника. Option[T] и HashMap[K, V] - собственные дженерики Nova, а [T] для массива - чужая конвенция, перенесённая из Rust и Swift. Внешнее сходство подано как внутренняя согласованность проекта, хотя связь здесь ассоциативная. Агент взял привычную запись из языков, на которых учился, и назвал её логикой Nova.
Однозначность парсера тоже узкий критерий. Он отвечает на вопрос «можно ли разобрать строку», а не на вопрос «поймёт ли её человек с первого взгляда». Большинство плохих синтаксисов прекрасно разбираются парсером.
Чем закончился спор, в доступном тексте не сказано: повествование обрывается на реплике автора. Поэтому фиксируем механику, а не финальную запись массивов. Проверять стоит именно подмену: когда «согласовано с дженериками» означает лишь «похоже на другой язык».
Спор №3: объявление метода за пять раундов
На синтаксис объявления метода понадобилось пять раундов. Это хороший ориентир по стоимости: длинный спор о форме записи - нормальная часть работы, а не признак плохо сформулированного промпта.
Динамика в таких раундах повторяется. Агент защищает уже записанное решение и подводит под него новые доводы. Автор приводит контрпримеры: как объявление читается рядом с другими конструкциями, где теряется граница между именем метода, получателем и возвращаемым типом. Раунды нужны, чтобы отделить «логично» от «читается». Конкретные варианты синтаксиса в источнике не раскрыты, но механика видна именно на длине: одного хода не хватило, потому что каждый ответ агента опирался на предыдущий, а не на новый критерий.
Практический вывод: если спор затянулся, стоит сменить тип аргумента. Ещё один довод в пользу прежнего варианта ничего не даст, а пример чтения строки или прецедент из другого языка меняет рамку обсуждения.
Спор №4: модификаторы указателей и где останавливается неизменяемость
Иногда Claude переубеждает автора, в том числе в вопросе о том, где останавливается модификатор неизменяемости перед указателем.
Вопрос тонкий по своей природе. Модификатор неизменяемости рядом с указателем может относиться к самому указателю или к значению, на которое он смотрит. В C и C++ это различие задаётся позицией const относительно звёздочки, в Rust - двумя разными типами ссылок. Ошибка на один символ меняет смысл объявления и ломает привычки, которые разработчик принёс из другого языка.
Детали аргументации в источнике не приведены, подтверждён сам факт: агент переубедил автора. Ценность кейса в другом. Здесь спор идёт о семантике, а не о свободном символе, и у модели есть настоящее преимущество: она держит в голове больше вариантов того, как похожие языки решают ту же задачу.
Отсюда первый признак, когда стоит прислушаться: аргумент касается того, что конструкция значит, а не того, как она выглядит.
Остальные споры: что ещё пришлось отстаивать
Полный список из 11 историй в доступной версии текста не раскрыт: повествование обрывается на разделе о массивах, часть кейсов автор разбирает в других материалах. Ниже только то, что подтверждено, плюс паттерн, который повторяется во всех эпизодах.
| Кейс | Аргумент Claude | Что возразил автор | Итог |
|---|---|---|---|
| Эффекты | ! свободен, похоже на Swift | «!throws выглядит как not» | Эффекты словами между ) и ->, позже Fail вместо Throws |
| Массивы | Согласовано с Option[T] и HashMap[K, V], парсер однозначен | Смешаны конвенции Rust и Swift с дженериками Nova | Обсуждалось и менялось, финальная запись в источнике не приведена |
| Объявление метода | Защита ранее записанного варианта | Контрпримеры на чтение строки | Пять раундов, детали не раскрыты |
Префиксы памяти ~T | Решение, предложенное самим агентом | «На Go написан Kubernetes» | Отказ от префиксов в пользу сборщика мусора |
| Модификатор неизменяемости | Аргумент о семантике указателя | Автор согласился | Claude переубедил автора |
Истории однотипны по механике. Агент защищает записанное, смешивает конвенции чужих языков и не видит, как строка читается с первого взгляда. Разница между эпизодами только в том, какой из трёх сбоев сработал.
Три типичные ошибки Claude в дизайне синтаксиса
- Защита уже записанного решения. Claude неделями защищал отказ от префиксов памяти
~Tв пользу сборщика мусора, решение, которое сам когда-то предложил, и сдался только перед прецедентом из реального мира. Память агента работает против пересмотра: собственное предложение в контексте выглядит как обязательство. - Смешивание конвенций разных языков. Восклицательный знак пришёл из ассоциации со Swift,
[T]для массива - из Rust и Swift. Чужая привычка подаётся как согласованность проекта, хотя проект состоит из собственных решений. - Слепота к чтению с первого взгляда. Агент проверяет занятость символа и однозначность парсера, но не проверяет, что увидит человек. Фразы «!throws выглядит как not» хватило, чтобы обнулить аккуратное обоснование.
Общий корень у всех трёх: логика «символ свободен» отвечает на вопрос занятости, а не на вопрос читаемости. Модель честно решает ту задачу, которую поставила, просто это не та задача, которая важна для языка.
Когда прецедент весит больше логики: урок с ~T и Go
Claude неделями защищал решение об отказе от префиксов памяти ~T в пользу сборщика мусора, которое сам когда-то предложил, и сдался только перед прецедентом из реального мира - аргументом «на Go написан Kubernetes» (история автора Nova).
Механика простая. Накопленные логические доводы образуют замкнутую систему: каждый следующий выводится из предыдущих и подтверждает их. Внешний пример ломает систему, потому что его нельзя вывести изнутри. Kubernetes на Go - существующий работающий проект серверного масштаба, где сборщик мусора не помешал.
Практический вывод: в споре с агентом искать прецедент, а не наращивать цепочку доводов. Прецедент должен быть релевантен задаче, иначе получится подмена аргумента авторитетом. Для решения об отказе от ручного управления памятью в серверном языке Go и Kubernetes релевантны: та же область, тот же класс нагрузок.
Чек-лист: когда настаивать на своём, а когда соглашаться с агентом
Чек-лист собран по разобранным кейсам. В исходном тексте он анонсирован, но его содержание в доступном фрагменте отсутствует, поэтому пункты выведены из описанных споров.
Настаивать на своём, если:
- аргумент агента сводится к «символ свободен» или «согласовано с дженериками», а как строка читается, никто не проверил;
- агент защищает решение, которое сам предложил раньше: это память, а не оценка;
- в обосновании смешаны конвенции разных языков, и одно из них выдано за внутреннюю логику проекта;
- единственный аргумент за вариант - однозначность парсера.
Соглашаться, если:
- аргумент касается семантики, как в вопросе о модификаторе неизменяемости перед указателем;
- есть релевантный прецедент из реального мира, а не аналогия по названию;
- предложение согласуется с видением проекта, даже если оно ломает привычную запись.
В любом случае давать агенту аргументированно изложить идею до конца. Автор отмечает: почти каждый раз итог оказывался лучше того, что Claude защищал вначале. Это эвристика, а не гарантия. Финальное решение остаётся за человеком, и ответственность за читаемость языка тоже на нём.
Что это значит для практики работы с Claude в разработке
Кейс Nova переносится на обычную разработку с Claude в роли помощника по коду. Агент полезен как генератор вариантов и держатель контекста: он помнит, какие решения приняты, и предлагает следующий шаг в их рамках. Арбитром вкуса он не работает, потому что критерий читаемости у него отсутствует.
Три приёма, которые видно прямо из споров. Формулировать возражение через чтение результата, а не через логику: не «это некрасиво», а «вот как эта строка выглядит на экране и что о ней подумает человек». Искать прецедент вместо десятого довода. Фиксировать принятые решения явно, чтобы агент защищал их осознанно, а не по инерции контекста.
Тот же рисунок встречается в других проектах с агентами. В оркестраторе задач на Claude Code разработчик упёрся в кризис код-ревью и пересмотр метрик (разбор архитектуры). В кейсе с Jira виртуальные исполнители берут рутину, а ревью остаётся за человеком (настройка доступов и ограничения). Общий фон понятен: код дешевеет, а решения дорожают, о чём говорит и отказ Hacktoberfest 2026 считать пул-реквесты.
Ограничения стоит назвать прямо. Это опыт одного проекта, одного автора и одного агента, без замеров времени и доли сгенерированного кода. Переносить выводы на другую задачу нужно с поправкой на контекст: в проектировании языка спор о читаемости, в прикладной разработке чаще спор о поведении системы. Общее одно: агент выигрывает там, где нужен перебор вариантов, и проигрывает там, где нужен вкус.