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

Это метод проекта — что становится скиллом, что кодом и почему именно так. Файл
читают перед правкой и ещё раз при ревью: против него судится каждый дифф
(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 layer                       | Harness при этом не меняется                                                                                    | Оттуда плагин переживает `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 за месяц) взяты правила, которые ложатся на этот раздел и на
«Когда добавлять механизм»:

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