RUGitHubInstall

Как строить Иву: принцип колеса

Это метод проекта — что становится скиллом, что кодом и почему именно так. Файл читают перед правкой и ещё раз при ревью: против него судится каждый дифф (ADR-0004). Термины — по CONTEXT.md, принятые решения — в docs/adr/.

Одно правило держит остальные. Если проблему можно решить скиллом — решаем скиллом. Код пишем только там, где нужна детерминированность. Принцип колеса: чем меньше в системе трущихся деталей, тем дольше она едет.

1. Скилл или код

ШагКлючевой моментПочему
Начинай новую задачу с вопроса «а не скилл ли это?»Спрашивай до первой строки кода, на каждый issue и каждую фичуПовторяющийся ответ в этой кодовой базе — скилл, то есть markdown-файл, который читает агент, а не новый механизм в TypeScript
Надо думать, адаптироваться, уточнять — скиллСуждение, интерпретация, уточнение намерения и процедура живут в скиллеСуждение не раскладывается на ветвления; попытка даёт захардкоженную эвристику там, где надо было прочитать текст и подумать
Одинаковый вход всегда даёт одинаковый выход — кодСюда же lookup, список и статус-чекМодель рассадит восьмерых гостей за столом, а на восьмистах напишет правдоподобную чушь
Поведение зависит от контекста разговора — скиллХод модели этот контекст уже несётКоду тот же контекст пришлось бы передавать целиком и руками
Скилл описывает КАК, а не ЧТОКонкретику подставляет вызов: один скилл с разными параметрами — разные способностиMarkdown здесь не документация, а код: процедура записана на языке, на котором модель и так думает
Harness держи тонкимHarness — программа, которая гоняет модель: цикл, файлы, контекст, безопасность. У нас это eve плюс минимальный слой интеграции — Channel, Bridge, несколько корневых инструментовЖирный harness с десятками tool-обвязок съедает половину контекстного окна: втрое больше токенов, втрое больше латентности, втрое больше отказов
Ценность держи в скиллахHarness только доносит скилл до моделиСкилл — файл: его видно, его легко поправить, он не ломает чужие установки

Примеры из своей же кодовой базы.

МеханизмСторонаПочему
iva doctorКодДиагностика установки на одном и том же состоянии выводит одно и то же
BridgeКодLong-polling обязан работать, когда агент занят или завис
Очередь ходов, миграции юнитовКодПорядок и атомарность, причём на чужих машинах без человека рядом
BrainКодБэкап, граф ссылок и Alert — один вход всегда даёт один результат
RollupКод + 4 коротких скиллаМодель судит о смысле дня, а код держит порядок, схемы, CAS, записи и Ceiling
Спавнер ScheduleКодЗапуск по времени обязан быть точным; он запускает единый кодовый memory-night

2. Что живёт только в коде

Детерминированный код — территория доверия: одинаковый вход даёт одинаковый выход. Пять свойств markdown не гарантирует никогда.

СвойствоКлючевой моментПочему markdown не может
Идентичность события и дедупликацияОдин и тот же апдейт обрабатывается ровно один разТекст не помнит, что уже видел, а сравнение ключей — операция, и её кто-то должен выполнить
Атомарность, локи, состояниеЗапись либо целая, либо её нет; параллельные ходы не топчут друг другаПосле краша нужен точный протокол восстановления, а не пересказ намерения
Точное времяРасписания, таймеры, таймауты, дросселиМодель время оценивает, а часы его измеряют
Безопасность, лимиты, деньгиAllowlist, Gate, потолки расходовИнструкцию можно переспорить словами, код нельзя, а цена промаха здесь чужая
ДоставкаНаружу всё уходит через Outbox, внутрь — через inbound pipelineОдин шов оставляет одно место, где проверяется каждое сообщение

Код зарабатывает своё место доверием: очереди, миграции, безопасность, деньги. Всё остальное — скилл.

3. Плагин — единица расширения

Цель владельца: один агент служит одному человеку, а расти умеет сам, чужими руками и без форка (ADR-0008).

ШагКлючевой моментПочему
Расширяй Иву плагиномНе правкой Authored tree и не форком репозиторияПапку можно принести откуда угодно и унести куда угодно, а правка ядра остаётся у того, кто её сделал
Бери формат Agent PluginsПапка с plugin.json, рядом skills/ и mcp.jsonГотовый стандарт даёт плагины соседних экосистем даром, а свой стоил бы спеки, валидатора и изоляции от чужих плагинов
Код плагина — eve Extension или MCP-серверЧего плагинам не хватает в eve (решающие хуки, экраны без хода модели), дописываем сами — в eve или рядом с нейeve даёт только хуки-наблюдатели; ждать upstream — оставить человека без функции (ADR-0023)
Ставь плагин в Custom layerHarness при этом не меняетсяОттуда плагин переживает iva update, и его установка не может сломать install (ADR-0003)
Ставь из git-URL или локальной папкиРеестра нет и не планируетсяЦентральный список требует модерации, доверия и живого мейнтейнера, а даёт одно удобство поиска
При совпадении имён побеждает ближний слойРешение предварительное, утвердим его вместе с реализациейТак уже работает eve: одноимённый тул потребителя выигрывает у тула eve Extension
Skill — содержимое плагина, а не единица поставкиСтавят и удаляют плагин целиком; скилл внутри знает, как делать работуОдно понятие — одно слово, поэтому слово «расширение» как термин запрещено обоим (CONTEXT.md)

Принятый риск: bash внутри скилла плагина видит env процесса со всеми ключами инсталляции. Владелец отложил ступень 2 ADR-0005, поэтому чужой плагин получает токены вместе с папкой. Пиши это прямо в доке установки и в SECURITY.md.

4. eve правим сами: решает опыт человека

Мерило одно: у человека всё работает. Человек здесь — владелец Ивы, тот, кто её ставит и обслуживает, разработчик и сама модель за работой. Решение принимается по их опыту, а не по тому, чей это код (ADR-0019). eve мы пользуемся и правим её так, как нам нужно; upstream не ждём (ADR-0023).

ШагКлючевой моментПочему
Сначала бери то, что eve уже делаетПроверь запуском, а не по памятиГотовый механизм уже проверен и обновляется без нас; копия рядом — лишняя трущаяся деталь
eve мешает — правь eveПравка — обычный коммит в eve/ вместе с кодом Ивы; upstream не ждёмЧеловеку всё равно, чей это дефект и чьи сроки; ему нужен ответ (ADR-0023)
Своё решение — один механизм в одном местеОбщий слой для всех провайдеров, не правка на вендораЗаплатка на случай возвращается следующим случаем
Свою правку eve держит тестТест называет поведение eve, которое мы поменялиНовая версия eve, которая вернёт старое поведение, покажет красный тест, а не тихий двойной механизм
Новую версию eve бери, когда она что-то даётОбновление — наше решение, а не долг; issue в upstream — по желанию, ответа не ждёмКаждое обновление — перенос наших правок и прогон тестов границы; это цена свободы (ADR-0023)
eve пришла к нашему решению — сними своёУсловие снятия записано рядом с решениемДва механизма на одно поведение спорят друг с другом
Готовую гарантию systemd-таймера бери напрямуюВторой планировщик для неё не нуженГарантия уже есть и уже проверена; свой планировщик — та самая деталь, которая сотрётся

5. Когда добавлять механизм

ШагКлючевой моментПочему
Общий механизм заводи после двух реальных независимых потребителейОдин потребитель — это функция, а не механизмОбобщение по одному случаю угадывает будущее и обычно угадывает мимо
Баг закрывай дизайном, а не одним тестомСначала измени дизайн так, чтобы весь класс таких ошибок стал невозможен. Тест подтверждает эту гарантию, а не заменяет еёТест ловит один случай, дизайн закрывает всё семейство
Лимит, порог и настройку держи одной константой в одном файлеВсе потребители — код, промпт, кламп, дока — читают одну точку; копий и хардкода нет, правка поведения системы = правка одной строкиКопии разъезжаются молча: продублированный лимит после первой правки живёт несколькими разными жизнями (CORE_CAP — эталон: один файл, три потребителя)
Считай новый механизм новой трущейся детальюЕё надо тестировать, ревьюить, мигрировать у сотен чужих инсталляций и когда-нибудь чинитьКаждая новая деталь в коде — та, что сотрётся: система должна оставаться простой настолько, чтобы её чинил обычный механик в поле (KISS Келли Джонсона)
Сначала спроси, что это уже даёт бесплатно: git, модель, существующий шовСнимок, копия «на случай отката», сторож и проверка не заводятся, пока не проверено, что историю уже хранит git, решение примет модель по инструкции, а шов уже естьГениальное решение простое. Ночь держала CORE в памяти процесса и объявляла «после сбоя не восстановить», хотя каждая правка vault уже была коммитом: откат — git show, а модели достаточно строки «сломалось — смотри историю» (T96, 26.09.2026)

Запрещено. Каждый пункт — механизм, который уже пробовали.

ЗапрещеноПочему
SQLite ради одной картыДвижок ради одной записи придётся мигрировать, а файл справляется сам
Generic delivery-подсистемаДоставка уже есть, и это Outbox; вторая заводит второе место, где сообщение теряется
Локальный fallback провайдераТихая подмена модели прячет отказ вместо того, чтобы его показать
Парсинг внутренностей eve снаружиНужно поведение внутри eve — правь eve (ADR-0023); кто читает кишки снаружи, ломается на каждом обновлении
Удаление по mtimeВремя файла врёт после копирования и восстановления, а платят за ошибку данными пользователя (ADR-0002)
Blacklist как security-границаСписок запрещённого закрывает только то, что автор вспомнил
Исправление дрейфа документации кодомДоку чинит правка доки; код поверх неё лишь прячет расхождение
Снимок файла в памяти процесса ради откатаИстория vault — это git: каждая правка — коммит, откат — git show; копия в памяти умирает вместе с процессом и рождает ложный остаток «не восстановить»

6. Тесты

ШагКлючевой моментПочему
Парсер, валидатор, резолвер и инвариант состояния покрывай property-тестомfast-check: генератор перебирает вход, свойство держит инвариантЭджи живут там, куда фантазия автора не дошла: юникод-мусор, пустая строка, гонка, вырожденное состояние
Провал обязан печатать seedТот же seed воспроизводит провалСлучайный тест без реплея шумит вместо того, чтобы показать поломку
Example-тест оставляй якоремКонтракт, формат сообщения, известная регрессияЯкорь читается человеком и держит ровно то, что обещано наружу
Входных случаев больше десятка — бери генераторПеречисление на этом объёме уже неполноеСписок растёт линейно, пространство входов — нет

7. Контекст

ШагКлючевой моментПочему
Считай узким местом контекст, а не интеллект моделиМодель ломается на незнании схемы данных, путей и наших слов, а не на сложности задачиВся работа вокруг агента — дать правильный контекст в правильный момент и не утопить модель в шуме
Держи инструкции указателямиAGENTS.md и памятки ссылаются на документы, а не содержат ихДвадцать тысяч строк накопленных заметок в системном промпте размывают внимание модели быстрее любого слабого чекпойнта
Правила владельца - отдельный живой файлВстроенная инструкция - карта; правила пользователя лежат рядом и читаются с диска каждый ходПравка встроенного файла замораживает его на дне правки и прячет всё, что приедет релизом
Роутинг контекста поручай description скиллаНаписал хорошее description — построил резолверМодель сама сопоставляет запрос с описанием и подгружает процедуру тогда, когда она понадобилась
Память развивай как суждение, а не как поискПрочитать пятьдесят документов и написать одну страницу: что субъект говорит, что делает на самом деле, что изменилось и где противоречиеТакой страницы не даёт ни SQL-запрос, ни поисковая обвязка; Vault и ночной Rollup — ровно эта механика

Способность модели прочитать много и написать страницу суждения мы называем диаризацией. Слово называет способность модели; ночной процесс зовётся Rollup.

8. Одноразовой работы нет

Задача, которая встретилась один раз, встретится снова.

ШагКлючевой моментПочему
1. Сделай руками на нескольких примерахПокажи результат владельцуПроцедуру не запишешь, пока не увидишь, как она ломается на живых данных
2. Одобрено — оформи скилломСкилл держит процесс, конкретику подставит вызовФайл переживает разговор, а разговор забывается
3. Должно происходить само — повесь на Schedule или systemd-таймерНочной ход запускает тот же скиллРабота без человека рядом — единственный способ накопить систему

Тест: если об одном и том же пришлось попросить дважды — система провалилась.

Оформленный скилл — необратимый апгрейд: он не деградирует, не забывается и умнеет с каждой новой моделью. Латентные шаги умнеют вместе с моделью, детерминированные остаются надёжными. Система накапливается: собрал один раз — работает всегда.

9. Формальная проверка: TLA+

Решение владельца 26.09.2026. Тест проверяет примеры, спека TLA+ перебирает все порядки событий. Там, где два процесса делят один файл, замок или очередь, тестам мало: гонку, которую автор не вообразил, тест не поймает. Спеки и их инварианты лежат в specs/.

ШагКлючевой моментПочему
У модуля с гонкой есть спека и список инвариантовЗамок fs-atomic, напоминания reminder-tick, ночные задания schedule-runner: specs/<модуль>.tla и .cfg рядом с кодомИнвариант «в критической секции один держатель» или «напоминание приходит один раз» доказывается перебором состояний, а не рассуждением в комментарии
Рассуждение о гонке живёт в спеке, не в комментарииКомментарий «здесь поздний release не снимет чужой замок» становится строкой инварианта, которую проверяет TLCКомментарий никто не перепроверяет после правки; спеку гейт перепроверяет при каждом изменении файла
Изменил охраняемый код — гейт гонит модельКонтрпример TLC красный: в отчёте порядок шагов, который ломает инвариант; код изменился, а спека нет — тоже красныйТа же логика, что у тестов: доказательство должно быть свежим относительно кода
Контрпример сначала становится тестомПо шагам контрпримера пишется падающий тест на этот порядок событий, только потом чинится кодТест держит найденную гонку после того, как спека уже доказала исправление
Инвариант нельзя ослабить в одном коммите с кодомУбрать или смягчить инвариант ради зелёного гейта — тот же обход, что удалить тестАгент чинит код, а не проверку

Из доклада Лорен Тан (2 500 PR за месяц) взяты правила, которые ложатся на этот раздел и на «Когда добавлять механизм»:

ПравилоКак применяем
Агент сам доказывает, что работа верна; доверие растёт только от этогоПриёмка требует доказательство запуском: смок, замер, контрпример или его отсутствие, а не «тесты зелёные»
Ошибку закрывать на самом сильном уровне: код → статический анализ → правила и скиллы → стайлгайдПоправил агента дважды на одном и том же — пиши правило линтера или меняй код так, чтобы ошибка стала невозможной; строка в правилах — последнее средство
Садовник и один проторенный путьОбходной путь с комментарием «временно так» расходится по коду как вирус; его останавливают правилом сразу, вычищают потом
Правильность и качество — разные вещиПравильность даёт проверка (смок, спека), качество дают скиллы с опытом; одно другим не подменяется
Скилл проверки = готовая команда плюс карта фичКоманда запускает приложение и снимает замер одинаково каждый раз; карта фич говорит агенту, как дойти до экрана и что считать успехом
View original Markdown ↗