Comments 65
Учитывая количество статей на Хабре про ИИ и вайбкодинг - лично я этой неожиданно ставлю "лайк".
Фактически это что-то в духе spec-driven development (для него есть фреймворки). Но тут заточено под более любительскую разработку (а не полное TDD + куча ограничений) - и лично мне представляется более гибкой и удобной. Имхо по сути весь Vibe++ - список требований к генерации нейросети, которые неплохо бы не забыть (уровень документированности, используемые технологии и пр.)
Ой, спасибо. Ждал первого комментария и взял даже тряпочку, чтобы обтираться =) А тут столько добра. Спасибо большое.
Спасибо за инструмент — я его сразу применил. Взял пример из статьи, добавил документацию по своей методике и проект (ИИ-психопрофилирование через адаптивный диалог в мессенджере MAX), прогнал через vibepp-prompt-rubik — и получил готовый промпт для Cursor, который задал вопросы и сгенерировал все артефакты по спек-листу.
Итог: SPEC на 9 блоков, vibepp.yaml, git-стратегия, GitHub Issues по итерациям. Репозиторий уже открыт: github.com/Quantum-Insight-Lab/aeon_map_system — пока без README, но docs внутри.
Если интересно, как Vibe++ лёг на нетехнический проект с психологической моделью в основе — готов показать детали.
это не язык, а описание структуры ТЗ или отдельно взятой задачи (если что, извините :-) ) )
=) Пусть новички думают, что знают язык программирования. Но формально, конечно же, это пока структура, не язык, вы правы, но кто знает, может мы совместно сделаем язык. Главное начать.
Чтобы начать что-то делать, нужно понимать что, как и зачем. Вы можете это сформулировать? Или учитывая контекст вашей статьи, “написать программу”, что как и зачем нужно разрабатывать подобный язык программирования :-)
Ну, например, я бы с радостью услышал предложение о том, как вкрячить в Vibe++ исправление ошибок и управление техдолгом, бэклогом. Кстати, отличная у меня идея про блок backlog, чтобы система сразу знала к чему готовиться =)
беклог, это не про кодирование, а про планирование. И к непосредственному программированию имеет слабое отношение
Ну давайте поспорим. Если знать к чему готовиться, то сразу закладываешь в архитектуру нужные модули. Например, если бы в моем примере я заложил функцию управления кубиком, то LLM мне бы сразу предусмотрела модель, управляемую, сделала бы нужные хелперы (пустые), но сделала бы. Так что тут это не лишнее.
Сложно об этом спорить, так как на вкус и цвет все фломастеры разные.
Просто по моему опыту не имеет смысла ставить очень долгоиграющие задачи без промежуточного контроля. И это в случае людей, а для LLM это вообще фундаментальное ограничение на длину контента (качество, время, деньги).
В этом случае длительное планирование становится бессмысленным для разработчика и нужно только для руководителя проекта или архитектора. Поэтому и затаскивать следующую задачу из беклога для разработки большого смысла не имеет.
Единственный вариант, когда в этом появляется смысл, это когда вы делаете не язык программирования, а какую нибудь автономную систему разработки кода (скайнет, например :-) ) и у нее есть функциональность системного анализа и планирования работ. Разбивает на подзадачи, анализирует на согласованность и взаимное влияние.
Но даже в этом случае беклог, как отдельная подсистема, будет нужна только для взаимодействия с внешним миром минуя репозитарий кода. А если все и так находится вместе с кодом, то можно обойтись несколькими файлами и “беклог”, как система, становится ненужной.
Ну вот простой пример. Вы делаете какое-то приложение, делаете его на русском языке, но при этом не закладываете файл локализации, потому что не думаете о том, что вам потом захочется сделать китайскую версию. Если в бэклог поместить мультиязычность, то LLM сразу создаст файл локализации, для одного языка. А потом просто хоп, сделает перевод на китайский и приложение будет поддерживать сразу два языка. Это касается доменного подхода к хранению данных, использование очередей и шардинга для высоконагруженных систем и т.п. Ставить цели надо масштабные.
Ну да, а теперь оборачиваем все это в агент/сабскилл, что бы на любое пользовательское "А что, если сделать программу для фиксации результатов анализов и сбора информации? Сделай мне программу" следовало интервью, на выходе формирующее спеку... Ой, да это же plane mode получается! ;)
Не, ну а так-то и правда паркуа бы не па?
Же сью контант де ву ву а =) (фр.) Очень рад вас видеть.
Слушайте, хаос надо немного структурировать, ну как иначе? Пусть вайбкодят все, я же только за, но посмотрите примеры, разница же очевидна. Ну раз лучше работает, пусть пользуются.
Следом добью Markdown с формальным описанием, а дальше будет круче. Скармливаешь шаблон описания в чат и говоришь, сделай мне ТЗ в этом формате, потом немного причесываешь и в светлое будущее стартап запускаешь.
Можно сказать что это Obsidian для ИИ, но в более строгой форме, интересно в каком направлении всё это пойдёт?
Кстати крутой пост, не ожидал что в 90% постах про ИИ найдётся такое золото!
Спасибо за статью:)
Vibe++ это очень детальный формат, и в полном виде для моего скромного проекта может быть overkill.
Сделал себе PLANNING.md и там два формата:
Базовый - краткий чеклист.
Полный - Vibe++ для проекта с полной структурой и примером использования.
Посмотрим, насколько это пригодится:)
Желаю удачи, поделитесь потом результатом. Вот тут описание поподробней https://stukalin.ru/vibepp/vibepp.md
Я крайне редко пишу негативные комментарии. Но тут не удержусь.
Чем дальше я продвигался по статье, тем больше надеялся, что в конце автор пояснит, в чём суть шутки. А оказывается, и автор и комментаторы воспринимают это серъёзно.
Если кто-то дочитает до моего комментария, и также будет считать, что это серьезно, ответьте мне пожалуйста:
в то время как Vibe++ вариант всего 50 Мб
Даже если учесть, что наверняка львиную долю этих 50 Мб составляют файлы или кодировки изображений, разве это не маркер, что автор вас разыгрывает?
А автор и читателей не смущает, что подобного результат можно добиться, если из всего текста на Vibe++ оставить (по моим оценкам) пять предложений? Остальное можно просто выкинуть или заменить другими словами.
Рискну предположить, что и одного предложения хватит. LLM видела тысячи страниц с анимацией кубика Рубика и наверняка справится.
А что делать, если страниц надо много, и они должны взаимодействовать? Во что превратиться тогда ваше Vibe++ описание?
Если Вы, автор, написали это на полном серъёзе, то поверте мне: это тупик.
Посмотрите, что делают другие, например, вот сюда: https://codespeak.dev/
Поверьте, мне, я знаю о чем говорю. Я разрабатываю много проектов, практически не прикасаясь к коду руками. Один такой проект описан недавно мной на Хабре: https://habr.com/ru/articles/1016102/
Не шутка потому что это инструкция для начинающих, ну что вы ей богу. Тому, кто знает что такое код - глупо объяснять как вайбкодить, он справится с этим и сам. Хотели пропиарится - класс. Сайт ваш мне понравился, я люблю такое, у меня похожий.
И чем идея отличается от идеи по вашей ссылке? Если бы я ее видел раньше, не стал бы писать статью, а с радостью описал этот сайт.. Но еще раз повторюсь - это я написал для тех, кто только постигает азы, ну вчитайтесь в введение.
И чем идея отличается от идеи по вашей ссылке?
Я не уверен в успехе начинания Андрея Бреслав (это его стартап). С ним, кстати последнее время несколько видео на YouTube опубликовано, например вот это: https://www.youtube.com/watch?v=0lBmqwlkWVI Советую посмотреть.
Подозреваю, они надеются как-то научить LLM (возможно через тюнинг, возможно с помощью RAG) генерировать по спекам код и наоборот.
А Вы просто предлагаете очередной формат для спецификаций в надежде, что он лучше других подойдет для LLM. А почему? Где аргументы? Где эксперименты? Где сравнения с другими?
В общем, погорячились Вы с таким сравнением.
блок
technologyфиксирует стек;блок
architectureзадаёт желаемый подход;
У меня сложилось как раз противоположное ощущение. Не нужно стремиться фиксировать и навязывать своё, уж тем более этого не стоит делать новичкам. Он там где-то может услышал что-то и наплетёт ей всякого. Модель очень редко возражает, чаще подчиняется и старательно делает любой бред. Много раз уже у меня было такое, что если ей сказать "предложи решение, подход", описав не задачу, а проблему или цель, которую хочется получить, то результаты прямо удивляют в хорошем смысле. Это касается даже интерфейсов. Я не являюсь дизайнером, да и дизайнеры часто чушь городят, а модель бывает просто из миллионов известных ей решений предлагает что-то вполне подходящее, если требования не очень жёсткие, конечно. Если прямо хочется что-то очень конкретное, бывает намного сложнее ей объяснить.
Так что вместо фиксации стека и архитектуры, предлагаю больше общаться с моделью, не жалея токенов в режиме планирования. Чтобы их всё-таки сэкономить, можно в другом чате поизучать явно тёмные моменты, ведь она знает практически всё, что знает человечество, а мы - нет. Спрашивайте совета как при общении с толковыми программистами. Уточняйте сомнительные моменты. Если видите, что это не то, что нужно, конечно, смело говорите ей просто как сделать. Но всегда полезно предложить ей потом оценить правильность подхода, поискать недоработки и сомнительные места даже когда план уже готов. Она может выдавать иногда улучшения ради улучшений, тут уже от качества модели многое зависит.
И вот еще в который раз удивляюсь зачем прямо сразу всё описывать. Это невозможно и так не делаются продукты и даже люди эволюцией получались постепенно. Даже обычная разработка давно использует спринты и прочее, когда команда тупо не знает толком куда будет двигаться дальше и с какой скоростью. Это ж не вагоны разгружать. Любой продукт - развивающаяся система. Но то, что с командой занимало бы недели и месяцы, с моделью может занять часы, поэтому не выходя из потока и не теряя энергии можно проверять сразу множество вариантов или даже полностью менять концепцию. И цена изменения архитектуры даже становится уже не такой большой, соответственно и значимость её выбора уменьшается.
Это называется ТЗ))
сложно представить что эти поля могу быть:
style: product_vibe:
- "cluttered"
- "dirty"
- "slowasfuck"
Если новичок хочет когда то стать специалистом, ему надо учится думать самому и задавать вопросы.
Это как разница между StackOverflow copy paste coding, и посмотреть 10 вариантов решения, понять каждое, понять где лучшее для твоео случая и почему.
В первом случае получается что то рабочее, но ты не знаешь как и почему это работает. Во втором случае ты получаешь что то рабочее но ты уже знаешь как и почему оно работает, почему это лучшее решение для задачи, и ты на шаг ближе к тому чтобы быть специалистом.
Vibe++ это инструкция с описанием того, что нужно знать модели. Новичкам будет легче, будь понятно с чего начать, прежде чем сожгут время
Я о том что работать с ИИ в режиме сделай мне это и то, это и есть сжигание времени.
Приведу пример, у меня 15 лет стажа в программировании и 0 в ремонтах и серьёзных умных домах. Но я делаю ремонт и хочу крутой умный дом, а специалисты которые могут такое сделать получают как минимум не меньше меня, у меня нет возможности их нанять. Приходится разбираться самому.
Так вот, когда я работаю с ИИ в программировании, Я вижу как "тупит" ЛЛМ. Я выступаю в роли техлида/тимлида, а ЛЛМ/агент в роли крайне исполнительного джуника. Я знаю на что смотреть когда делаю ревью ИИ кода, я знаю какой мне код нужен и могу поставить чёткую ясную задачу, легко вижу когда решение ей соответствует, когда это хорошее решение, когда нет, почему нет.
С ремонтом ситуация ровно наоборот. Каждый ответ ЛЛМ выглядит правильным и логичным. Но стоит начать задавать вопросы как выясняется что это даже не ответ а сферический конь в вакууме. Вменяемый ответ получается только после десятков часов общения плюс десятки часов размышлений, когда я достаточно потыкал тему с разных сторон, и уже в ней ориентируюсь.
Мой комментарий как раз об этом, если Вы новичок который хочет стать специалистом, учитесь критическому мышлению а не вайбкодингу, задавайте вопросы а не раздавайте задания, чтобы ставить хорошие задания надо хорошо разбираться в теме.
Есть люди, которые не хотят вообще программировать, но хотят запустить стартап. И у них теперь есть инструмент в виде относительно бесплатного ИИ. Я согласен, что глюки моделей, ошибки в коде, уязвимости - все это будет, но этого точно будет меньше, если правильно поставить задачу.
Если речь о новичках которые не хотят быть специалистами, ИМХО, легче поговорить с ЧатЖПТ, описать что ты хочешь, попросить придумать решения и описать что они дают. Когда понимание ЧатЖПТ выглядит достаточным, попросить составить промпт для кодинг агента. Это интуитивно понятнее и проще чем пытаться описывать задачу самому, и нет желания разбираться в деталях.
Что то типа, есть идея для бизнеса, хочу продавать нумерологические прогнозы через телеграм бота, помоги мне составить техническое задание/BRD. Задавай вопросы, один за раз, пока у тебя не будет достаточно информации чтобы составить детальное, качественное техническое задание, когда будешь готов сделай ТЗ как маркдаун файл который я могу скачать и отдать агенту на исполнение.
Ну наконец-то! ☺ То, что для общения с генераторами нужен спецязык, выглядело очевидным с самого начала. Существуют декларативные языки вроде Prolog – может, продуктивно было бы его приспособить?
Более технический подход - скетч программирование))
https://github.com/DmitryOlkhovoi/Sketch-programming
// @sketch:reactComponent
// @ext:tsx
Component Count
props add = 0
state count = 0
effect {
console.log("Component mounted");
cleanup {
console.log("Cleanup");
}
}
<div onclick="count += add"> Will add {add} </div>
<div>
Current count: {count}
</div>Такие фреймворки понятны программистам. Я люблю фреймворки, с детства их создаю. Vibe++ - это естественный слабо структурированный язык, даже больше шаблон, позволяющий просто немного поток мыслей непрограммиста направить в нужное и понятное LLM русло.
Обычный SDD.
Можно модели сказать и она по словесному описанию или интервью сгенерит спеку, потом его вручную подправить.
Вы сильно переоцениваете возможности и желания типового непрограммиста. Да и программиста тоже. Никто не хочет писать с нуля, да ещё и используя новый язык, который перед началом работы надо загрузить в мозг. Пусть даже это спека в формате YAML. Я, заради интерса, вставил спеку в Word. 7 страниц. Да, можно убрать лишние вертикальные интервалы, будет 5. Это всё равно очень много. Пять страниц технического описания - в реальном проекте не каждый аналитик напишет за полный рабочий день.
Это может взлететь в режиме опросника - когда отдельный генератор или сама LLM задаёт вопросы по такой спеке, а пользователь (в данном случае - будущий потребитель продукта) показывает пальчиком - это мне надо, это не надо. И то после первых пятнадцати минут скажет "что-то дофига сложно", потому как устанет.
7 страниц реально ту мач. Я как яркий представитель вайбкодера, который класс от библиотеки не отличит, и до сих пор не знает правила нормальности в СУБД, могу сказать, что максимум только одна страница залетит)
Ну и еще с точки зрения системного анализа наверно имеет смысл в вайб++ добавить выпадающий список сразу "что система создаваемая должна делать": по критериям операционных либо линейных функций систем, либо гибридная. это может быть на уровне языка осин, но и это уже значительно бы облегчило экономию токенов в используемом ИИ-ассистенте. в целом поддержу ораторов, что лень правит миром, и жду выхода вайб++ в виде какой-нибудь утилиты/приложухи, или как там у вас это называется?)))
Может вам будет интересно мнение вайб-кодера:
ИМХО у идеи огромный потенциал - нам нужна прокладка между человеком, который не до конца понимает что он хочет и как это объяснить, и роботом, который не до конца понимает что от него хотят и вместо того чтобы спросить пытается угадать.
ИМХО надо избавиться от английского - не вижу смысла в использовании другого языка, все параметры - кирилица, так проще русскоязычным
Видится мне это в виде программы-оболочки (типа visual studio code)
Пользователь заполняет необходимые поля, которые ему предлагается заполнить (в статье указаны) и по правому клику на каждое свое утверждение, просьбу, предложение, мысль может установить предлагаемые оболочкой параметры (ограничения, обязательные условия, стиль и прочее уже заранее заготовленное и адаптированное под понимание робота)
Иметь возможность составлять не ТЗ "от и до", а "текущий промт" - начальные установки, с которых начинается работа над любой подзадачей внутри большого проекта. (Если интересно могу показать свой "текущий промт", с которого начинается каждый новый чат с роботом. Внутри текущего промта я ставлю роботу конкретную задачу (каждый раз разную, но над одним и тем же проектом). Было бы здорово иметь оболочку, в которой можно было управлять не только всем ТЗ, но и задавать перманентные условия, требования, ограничения.
Иметь готовые шаблоны подходящие под большинство типовых задач. Я имею в виду возможность выбрать не "ЧТО должно быть", а "КАК должно быть"
В этом плане можно очень много чего предложить пользователю и помочь новичку избежать глупых ошибок, а также помочь продвинутому заниматься вайбкодингом в более удобной и функциональной среде, нежели просто строка промта
Сделал по примеру https://stukalin.ru/vibepp/vibepp-prompt-rubik.txt себе vibepp.yaml в https://github.com/Quantum-Insight-Lab/aeon_map_system. На 845 строк файл вышел...
Интересно, с текущей скоростью Composer 2.0 Fast такой проект в 2-3 человека за неделю соберут?
Красивое. Чат бот то получился?
Вайб-идеи кончились? Вернулись к коду? К кривому, но все же коду. А как же agi? Все, не ждем?
Это блять yaml
Идея правильная. Но не все ИИ следубт таким инструкциям.
Но это в разы лучше чем предлагают многие.
Я не пишу полотна с ИИ, я пишу мелкими кусками. Так вы строго контролируете процесс.
У меня есть наработка протокала, он сложнее того что описали вы, но похож не много. И мой вариант экономит до 95% токенов заставляя ИИ строго идти по инструкции.
Так что да, ваш подход хороший. Это описано во многих книгах и докумениации по работе с ИИ. Но их ни кто не читает… 😂
К каждой ИИ есть документация, там четко описано нечто подобное вашему, с ограничениями и пояснениями где ИИ хорошо сработает а где плохо.
У каждой ИИ свое причуды.
Основная проблема это рамытость… Для ИИ одно и то же предложение, без жёсткой конкретики, может сильно размыть результат. Но так же важна последовательность инструкций! Важно еще и чтоб их не было много! Ваш пример может в одном ИИ хорошо отработать, в другом запутаться… Особенно в рассуждениях… Есди вы пишите такую большую инструкцию, лучше выключать рассуждения. Иначе ИИ запутаться по итогу…
Отдайте данный текст любой ИИ и спросите что там. Она ответит очень точно, хотя там минимум данных. И их легко прочитать. Для ИИ это чистая логика, оно ее обожает. 😁
Вот этот текст который ниже:
PyDev(2+y) → Team/Product. Req: Docker, Redis, PG, Py3, DRF, Celery, AIOHTTP; Indices; REST, µserv, async; CleanCode/Tests/Docs; Git/Jira/GL. Stack: Ubuntu/CentOS(systemd); PG/Redis; Py3.7+(Django/AIOHTTP/DRF); Nginx/uWSGI/Gunicorn; Celery. Opt: Go. Offer: Office(Minsk/Krasavik); TK RB; FlexVacation; 5SickDays(100%); Sport/Eng/Edu paid.
Сразу задам вопрос, как просто и быстро в редактор ИИ написать мю и стрелочку? =) ИИ отлично прочитает инструкции и на ассемблере, прологе, с++ и на чем угодно, но Vibe++ - это yaml-стайл формат, который одинаково хорошо читает ИИ и люди.
при верном подходе. если вам реально оно надо, просто берете любую модель даже 1B, она вам это легко все составит как надо и пользуетесь. это не для коротких запросов! это протокол для сложного взаимодействия с ИИ и экономии от 65% до 95%. то есть, это не для поиграться. это для серьезной работы. можно и текстом, ни кто не против. но когда вы тратите в компании на ИИ 100 000 дол, экономия в 95% или даже 65% минимум, это очень много. Vibe++ подходит под простые задачи одиночек. а мой протокол про серьёзные задачи где надо четкие ответы. и там потратить даже на 3B модель (тестировал) 3-5$ в месяц чтоб экономить тысячи долларов, выглядит очень даже круто. точность там очень высокая, даже 3-7B по логике выходят на уровень 70B.
проект можно сживать до 80-95%, при этом ИИ будет четко знать что за ч то в нем отвечает. сразу скажу, тестировал в обычных форматах точность падает с 98% на 40-50%… а это огромные деньги. даже 3-7B справляются близко к уровням больших можделей.
26B модель, на обычном промпте, не смогла решить ни одной задачи. на моем протоколе она обогнала даже Kimi…
ваш подход тоже хорош. но он про другое.
vibepp: "0.2"
methodology: "PDA" # Possibility-Driven Architecture v1.1 (Максим, 2026)
# ═══════════════════════════════════════════════════════
# ÆON MAP SYSTEM — MAX BOT
# Машинная спецификация для агентной разработки
# ═══════════════════════════════════════════════════════
project:
name: "AeonMapMaxBot"
type: "conversational-ai-bot"
platform: "MAX (VK messenger, Bot API)"
summary: >
ИИ-бот в мессенджере MAX, который ведёт адаптивный диалог с пользователем
и строит многослойный профиль личности по архитектуре ÆON Map System.
Каждый ответ пользователя — это событие. Профиль — это read model поверх
event log. Диалог — это живая система, управляемая LLM-ядром и PDA-инвариантами.
purpose:
goal: >
Снизить неопределённость пользователя о себе: кто он, как думает,
чего хочет, где его ограничения, какой архетип, куда расти.
problem: >
Человек не понимает своих паттернов — когнитивных, эмоциональных,
стратегических. Существующие тесты (MBTI, соционика) статичны,
поверхностны и не дают персонализированного пути развития.
outcome: >
Пользователь получает ÆON-профиль: визуальная карта личности по 7 слоям,
текстовые инсайты, архетип, зоны роста, и Book of Consciousness —
история трансформации, которая пополняется при каждой сессии.
pda_framing: >
Приложение — это машина, которая снижает неопределённость пользователя
о себе, закрепляя устойчивые инварианты идентичности через акты
определённости (ответы в диалоге).
# ───────────────────────────────────────────────────────
# ПОЛЬЗОВАТЕЛИ
# ───────────────────────────────────────────────────────
audience:
primary:
- "люди в точке выбора: карьера, отношения, смыслы"
- "практики саморазвития, коучинга, психологии"
- "предприниматели и лидеры, строящие команды"
secondary:
- "коучи и терапевты (используют бот как диагностику)"
- "HR-специалисты (совместимость, роли)"
jtbd:
- "не понимаю, в чём моя реальная сила"
- "хочу понять свои паттерны, не проходя долгую терапию"
- "хочу видеть, как я меняюсь со временем"
- "хочу понять, почему у меня не выходит X"
# ───────────────────────────────────────────────────────
# КАРТА НЕОПРЕДЕЛЁННОСТИ (PDA Step 1)
# ───────────────────────────────────────────────────────
uncertainty_map:
user_level:
- "Как я думаю и принимаю решения?"
- "Что меня на самом деле мотивирует?"
- "Почему я повторяю одни и те же сценарии?"
- "Каковы мои реальные ценности, а не декларируемые?"
- "Где мои скрытые таланты?"
- "Что мне мешает — страхи, барьеры, тень?"
- "Какая среда и ритм жизни мне подходят?"
- "С какими людьми я в резонансе?"
- "Как я выгляжу в команде vs как себя чувствую?"
- "Куда мне развиваться в следующие 12 месяцев?"
system_level:
- "Насколько уверенно назначена та или иная карта?"
- "Не противоречат ли ответы пользователя друг другу?"
- "Готов ли пользователь к следующему слою?"
- "Нет ли признаков кризисного состояния?"
- "Корректен ли профиль или нужна калибровка?"
# ───────────────────────────────────────────────────────
# ГРАФ ДОМЕНА (PDA Step 3)
# ───────────────────────────────────────────────────────
domain_graph:
entities:
User:
fields: [id, max_user_id, created_at, locale]
note: "идентификатор из MAX, никакой PII за пределами этого"
Session:
fields: [id, user_id, layer, status, started_at, completed_at]
statuses: [active, completed, abandoned, paused]
Answer:
fields: [id, session_id, question_id, value, answered_at]
note: "неизменяемый факт — только append"
CardSignal:
fields: [id, user_id, card_type, weight, source_answer_id, source_layer, created_at]
note: >
копилка сигналов для карты; один ответ может породить несколько записей
(сквозной routing на разные card_type). Агрегация веса — вход для готовности Card.
Card:
fields: [id, user_id, card_type, confidence, version, computed_at]
card_types:
- CognitiveIdentityMap
- BehavioralPatternMap
- AeonConsciousnessMap
- AffectiveResonanceMap
- CoreValuesMap
- LatentPotentialMap
- StrategicSelfMap
- LimitMap
- EvolutionMap
- ArchetypeMatrix
- SocialPersonaMap
- ShadowMirrorMap
- RoutineGrowthMap
- EnergyFlowMap
- ResonanceMap
- CompatibilityMap
- LearningMap
- EnvironmentMap
AeonProfile:
fields: [id, user_id, glyph_code, activation_phrase, version, built_at]
note: "read model — пересобирается из events"
Glyph:
fields: [id, user_id, image_url, meaning, created_at]
note: "визуальный символ идентичности; OpenAI Images (DALL·E), см. SPEC Блок 4"
BookOfConsciousness:
fields: [id, user_id, entries]
note: "таймлайн трансформации — только append"
LlmCall:
fields: [id, session_id, model, prompt_version, input_hash, output, latency_ms, called_at]
note: "каждый вызов LLM фиксируется для воспроизводимости"
edges:
- "User has_many Session"
- "User has_one AeonProfile"
- "User has_one BookOfConsciousness"
- "User has_many Card"
- "User has_many Glyph"
- "Session has_many Answer"
- "Session belongs_to Layer"
- "Answer contributes_to Card (через event-проекцию)"
- "Answer contributes_signal_to Card (cross-layer; через CardSignal)"
- "User has_many CardSignal"
- "CardSignal targets Card by card_type (агрегация веса перед card.computed)"
- "Card aggregates_into AeonProfile"
- "Session generates LlmCall"
- "LlmCall produces next_question"
- "AeonProfile generates Glyph"
- "BookOfConsciousness records Session.completed"
# ───────────────────────────────────────────────────────
# ИНВАРИАНТЫ (PDA Step 4)
# ───────────────────────────────────────────────────────
invariants:
domain:
- id: INV-01
rule: "Session может иметь ровно один статус из {active, completed, abandoned, paused}"
enforcement: "domain validator + DB constraint"
- id: INV-02
rule: "Answer неизменяем после записи. Пользователь не может редактировать ответ — только пройти новую сессию"
enforcement: "append-only table, no UPDATE/DELETE in ORM"
- id: INV-03
rule: "Card назначается только при confidence >= CARD_CONFIDENCE_THRESHOLD (default: 0.72)"
enforcement: "Stability Engine, не LLM"
- id: INV-04
rule: "Card не может быть в двух взаимоисключающих состояниях одновременно (например, CognitiveType=Analytical и CognitiveType=Intuitive с равным весом без флага 'синтетик')"
enforcement: "domain validator перед записью Card"
- id: INV-05
rule: "Session следующего слоя не открывается, пока предыдущий слой не имеет минимум MIN_ANSWERS_PER_LAYER ответов"
enforcement: "Stability Engine"
- id: INV-09
rule: >
Card не назначается (card.computed), пока суммарный вес сигналов по card_type
< MIN_AGGREGATE_SIGNAL_WEIGHT_FOR_CARD — независимо от того, с каких слоёв пришли
сигналы; unlock слоя регулирует ход диалога, не заменяет порог сигналов
enforcement: "Stability Engine + агрегация CardSignal"
- id: INV-06
rule: "LlmCall сохраняется до выдачи ответа пользователю, не после"
enforcement: "транзакция: write LlmCall → send message"
- id: INV-07
rule: "Одно сообщение пользователя = не более одного Answer event (идемпотентность)"
enforcement: "idempotency_key = max_update_id"
- id: INV-08
rule: "AeonProfile пересобирается только из зафиксированных событий, никогда не редактируется вручную"
enforcement: "profile builder принимает только event store на вход"
safety:
- id: INV-S01
rule: "При обнаружении кризисных маркеров (суицид, самоповреждение, насилие) бот прекращает профилирование и предлагает горячую линию"
enforcement: "safety Gate 1 в stability/ на каждом пользовательском input до любого дорогого вызова; Gate 2 в system prompt LLM"
- id: INV-S02
rule: "Бот не даёт медицинских, юридических, финансовых советов — только рефлексивные вопросы и инсайты"
enforcement: "системный промпт + content filter"
# ───────────────────────────────────────────────────────
# КОНСТАНТЫ (PDA Step 5)
# ───────────────────────────────────────────────────────
constants:
- key: MIN_AGGREGATE_SIGNAL_WEIGHT_FOR_CARD
value: 0.5
why: "черновой порог суммарного веса (шкала 0–1); калибровать до запуска MVP"
breaks_without: "карты без смысла или слишком рано; либо игнор сквозных связей"
calibration: "A/B с retention и качеством профиля; зафиксировать число в docs/constants.md"
- key: CARD_CONFIDENCE_THRESHOLD
value: 0.72
why: "ниже — карта ненадёжна и вводит пользователя в заблуждение"
breaks_without: "профиль будет строиться на слабых сигналах"
calibration: "A/B по retention и user feedback после профиля"
- key: MIN_ANSWERS_PER_LAYER
value: 4
why: "меньше — LLM не имеет достаточно контекста для следующего слоя"
breaks_without: "профиль будет поверхностным, слои не связаны"
calibration: "анализ completion rate по слоям"
- key: MAX_QUESTIONS_PER_SESSION
value: 12
why: "больше — усталость, дропы; меньше — недостаточно сигналов"
breaks_without: "либо дроп в середине, либо слабый профиль"
calibration: "замер session_completion_rate по длинам"
- key: SESSION_IDLE_TIMEOUT_MIN
value: 30
why: "30 минут молчания = сессия брошена; восстанавливаем контекст при возврате"
breaks_without: "ghost sessions, утечка памяти в Redis"
calibration: "медиана времени между ответами + буфер"
- key: LLM_QUESTION_TEMP
value: 0.7
why: "достаточно вариативно для живого диалога, не галлюцинирует вопросы"
breaks_without: "слишком предсказуемо (0.0) или хаотично (1.0+)"
calibration: "blind A/B оценка качества вопросов операторами"
- key: DAILY_SESSION_LIMIT
value: 3
why: "защита от злоупотреблений и LLM-затрат; 3 сессии в день — норма"
breaks_without: "спам-атаки, неожиданные расходы"
calibration: "анализ percentile-99 по сессиям/день"
- key: MAX_BOT_REPLY_TIMEOUT_SEC
value: 8
why: "MAX UI показывает typing indicator; > 8 сек — пользователь думает, что сломалось"
breaks_without: "плохой UX, повторные нажатия, дубли"
calibration: "p95 latency LLM + overhead"
# ───────────────────────────────────────────────────────
# EVENT CORE (PDA Step 6)
# ───────────────────────────────────────────────────────
events:
schema_version: 1
contract:
required_fields:
- event_id # uuid v7
- event_type # snake_case string
- occurred_at # ISO 8601 UTC
- actor # {id, role}
- subject # {entity, id}
- payload # object
- idempotency_key # max_update_id или generated uuid
- schema_version # integer
optional_fields:
- causation_id # uuid предыдущего event
- correlation_id # uuid сессии/флоу
catalog:
- type: user.started
trigger: "первый /start в MAX"
payload: [max_user_id, locale, referral_source]
- type: session.opened
trigger: "бот открыл новую сессию"
payload: [session_id, layer, question_count_plan]
- type: question.asked
trigger: "бот отправил вопрос пользователю"
payload: [session_id, question_id, question_text, layer, llm_call_id]
- type: answer.given
trigger: "пользователь ответил"
payload: [session_id, question_id, answer_value, answer_type]
note: "НЕИЗМЕНЯЕМ после записи (INV-02)"
- type: card_signal.received
trigger: "ответ спроецирован на копилку сигналов целевой карты (сквозной routing)"
payload: [answer_id, user_id, card_type, weight, source_layer]
note: "может быть несколько на один answer.given; causation от answer.given"
- type: llm.called
trigger: "вызов Claude API"
payload: [session_id, model, prompt_version, input_hash, latency_ms]
note: "фиксируется до отправки ответа (INV-06)"
- type: card.computed
trigger: "Stability Engine назначил карту"
payload: [card_type, confidence, input_answer_ids, version]
- type: session.completed
trigger: "сессия завершена (все вопросы отвечены)"
payload: [session_id, duration_sec, answers_count, layers_covered]
- type: profile.built
trigger: "ÆON-профиль пересобран из событий"
payload: [profile_version, cards_included, glyph_id]
- type: safety.triggered
trigger: "safety Gate 1 (или реже Gate 2 / эскалация) поймал кризисный маркер"
payload: [session_id, trigger_category, action_taken]
note: "НЕ содержит оригинальный текст пользователя"
- type: session.abandoned
trigger: "SESSION_IDLE_TIMEOUT истёк"
payload: [session_id, last_answer_at, answers_count]
# ───────────────────────────────────────────────────────
# АРХИТЕКТУРА (PDA Step 6)
# ───────────────────────────────────────────────────────
architecture:
approach: "Event-sourced, domain-centric, stability-first"
layers:
max_adapter:
role: "принимает webhook от MAX, отдаёт ответы"
responsibilities:
- "парсинг MAX update"
- "идемпотентность по update_id"
- "форматирование сообщений и кнопок MAX"
must_not: "содержать бизнес-логику"
api_layer:
role: "HTTP endpoints, auth, rate limiting"
note: "только роутинг и валидация входа"
domain_layer:
role: "инварианты, валидаторы, доменные сущности"
must: "работать без I/O — чистый код"
must_not: "знать о MAX, LLM, БД"
stability_engine:
role: "лимиты, пороги уверенности, анти-абуз, safety Gate 1"
responsibilities:
- "проверка DAILY_SESSION_LIMIT"
- "проверка CARD_CONFIDENCE_THRESHOLD"
- "safety Gate 1: rule-based / лёгкий классификатор ДО любого дорогого вызова (отдельные тесты)"
- "rate limiter по user_id"
must: "быть отдельным модулем в src/stability/, не размазан по коду"
signal_classifier:
role: "шаг 1 пайплайна ответа: ответ → веса по card_type → card_signal.received"
responsibilities:
- "дешёвый: правила или малая модель, не обязательно LLM"
- "несколько card_signal.received на один answer при необходимости"
must_not: "блокировать p95 ответа тяжёлым LLM"
dialog_engine:
role: "адаптивный диалог, управление состоянием сессии"
responsibilities:
- "выбор следующего вопроса (через LLM или fallback)"
- "трекинг прогресса по слоям"
- "определение момента перехода к следующему слою"
must: "работать через events — каждый шаг = event"
llm_client:
role: "вызовы Claude API (основной диалог), OpenAI (fallback), промпты"
responsibilities:
- "системный промпт с контекстом пользователя + safety Gate 2 (границы в промпте)"
- "версионирование prompt templates"
- "логирование каждого вызова (LlmCall event)"
- "fallback: OpenAI при недоступности Claude"
- "глиф: OpenAI Images (DALL·E), не смешивать с текстовым Claude без явного разделения"
aeon_engine:
role: "вычисление карт, построение профиля; глиф через OpenAI Images"
input: "только event store"
output: "Card, AeonProfile, Glyph"
event_core:
role: "append-only event store"
storage: "PostgreSQL, таблица events"
must: "не иметь UPDATE/DELETE"
read_models:
role: "проекции для быстрого чтения"
models:
- "UserProfile (сжатый профиль: карты, confidence, архетип)"
- "CardSignalRollup (незакрытые сигналы по порогу)"
- "AnswerTail (последние 3–5 ответов для LLM)"
- "SessionContext (текущее состояние сессии для LLM)"
- "BookOfConsciousness (таймлайн; не в промпт LLM — UI и метрики)"
rebuild: "из event store при необходимости"
data_flow: |
MAX Webhook
│
▼
[MAX Adapter] ──idempotency check──▶ skip if duplicate
│
▼
[Stability Engine] ──safety Gate 1──▶ crisis: send hotline, stop (без LLM)
│ └──rate limit──▶ 429, stop
▼
[Dialog Engine] reads SessionContext + профиль + хвост + незакрытые CardSignal
│
├──▶ [Signal Classifier] ──▶ card_signal.received (дешёво)
│
├──▶ [LLM Client Claude; Gate 2 в system prompt] ──▶ llm.called ──▶ next question
│ └── fallback OpenAI при сбое Claude
│
▼
answer.given event ──▶ [Event Core]
│
├──▶ [Aeon Engine] ──▶ card.computed (порог сигналов + confidence)
│
└──▶ [MAX Adapter] ──▶ send message to user
stack:
language: "TypeScript 5.x"
runtime: "Node.js 22 LTS"
web: "Fastify"
database: "PostgreSQL 16"
cache: "Redis 7 (сессии, rate limits)"
llm:
primary: "Anthropic Claude API"
fallback: "OpenAI (текст)"
glyph_image: "OpenAI Images (DALL·E)"
share_render: "sharp + @resvg/resvg-js (SVG → PNG, без headless browser)"
migrations: "node-postgres + db-migrate | Drizzle ORM — уточнить при инициализации репо"
containerization: "Docker + docker-compose"
testing: "Vitest + fast-check (property-based для инвариантов)"
observability: "OpenTelemetry + Prometheus-совместимые метрики"
# ───────────────────────────────────────────────────────
# СТРУКТУРА ПРОЕКТА
# ───────────────────────────────────────────────────────
project_structure:
style: "domain-centric monolith (v1), готов к разделению"
directories:
- path: "src/domain/"
purpose: "сущности, инварианты, валидаторы — чистый код без I/O"
- path: "src/events/"
purpose: "event store, контракты, идемпотентность"
- path: "src/stability/"
purpose: "Stability Engine: лимиты, safety Gate 1, пороги (отдельные тесты на gate)"
- path: "src/dialog/"
purpose: "движок диалога, FSM слоёв, управление сессией"
- path: "src/signal_classifier/"
purpose: "дешёвый шаг: ответ → card_signal.received (правила или малая модель)"
- path: "src/aeon/"
purpose: "карты ÆON Map, профиль, глиф, Book of Consciousness"
- path: "src/llm/"
purpose: "Claude (основной), OpenAI fallback, DALL·E для глифа; prompt templates"
- path: "src/integrations/max/"
purpose: "MAX Bot API клиент, webhook handler"
- path: "src/read_models/"
purpose: "проекции: SessionContext, UserProfile, CardSignalRollup, AnswerTail, BookOfConsciousness"
- path: "src/api/"
purpose: "HTTP endpoints, роутинг"
- path: "tests/invariants/"
purpose: "property-based тесты на инварианты (Vitest + fast-check)"
- path: "tests/scenarios/"
purpose: "end-to-end сценарные тесты диалогов"
- path: "migrations/"
purpose: "SQL миграции (db-migrate | Drizzle — по выбору при старте)"
- path: "docs/"
purpose: "SPEC, SPEC_SUMMARY, uncertainty-map, domain-graph, invariants, constants, events, architecture, observability, roadmap, GITHUB_ISSUES, GIT_STRATEGY"
- path: "prompts/"
purpose: "версионированные prompt templates для LLM"
# ───────────────────────────────────────────────────────
# СЛОИ ÆON MAP — РЕАЛИЗАЦИЯ
# ───────────────────────────────────────────────────────
# Unlock order — линейный; signal routing — сквозной (см. SPEC Блок 2, CardSignal, card_signal.received).
aeon_layers:
mvp:
- id: I
name: "Core Layer"
cards: [CognitiveIdentityMap, BehavioralPatternMap]
min_questions: 4
unlock_condition: "session.started"
- id: II
name: "Emotional & Motivational Layer"
cards: [AffectiveResonanceMap, CoreValuesMap]
min_questions: 4
unlock_condition: "Layer I completed"
- id: IV
name: "Archetype Layer"
cards: [ArchetypeMatrix]
min_questions: 4
unlock_condition: "Layer II completed"
v1_addition:
- id: III
name: "Strategic Layer"
cards: [StrategicSelfMap, LimitMap]
- id: V
name: "Dynamic AI Layer"
cards: [EnergyFlowMap, ResonanceMap]
v2_addition:
- id: VI
name: "Integration Layer"
cards: [CompatibilityMap, LearningMap, EnvironmentMap]
- id: VII
name: "Meta Layer"
cards: [AeonConsciousnessMap]
note: "включает генерацию Glyph и Book of Consciousness"
# ───────────────────────────────────────────────────────
# ДИАЛОГ
# ───────────────────────────────────────────────────────
dialog:
mode: "adaptive — следующий вопрос генерирует LLM с учётом всех предыдущих ответов"
branching: "без явных веток сценария — только адаптивный LLM по полному контексту"
prompts:
structure: "один общий system prompt + дополнения/шаблоны по слоям (I, II, IV MVP)"
note: "отклонения (не знаю, оффтоп, провокации) — в рамках этой структуры, не отдельные продуктовые ветки"
fallback: "статичный список вопросов на случай LLM timeout"
answer_formats:
- type: buttons
use_when: "закрытые вопросы (выбор из 2–4 вариантов)"
max_options: 4
- type: free_text
use_when: "открытые вопросы глубокого слоя"
- type: scale
use_when: "оценка интенсивности"
range: "1–7"
persona:
name: "ÆON"
tone:
- "глубокий, но не тяжёлый"
- "любопытный исследователь, не судья"
- "конкретный — без воды и эзотерики"
- "тёплый, но не сюсюкающий"
boundaries:
- "не терапевт"
- "не ставит диагнозы"
- "не предсказывает будущее"
- "не сравнивает с другими людьми"
safety:
gates:
gate_1:
where: "src/stability/ — до любого дорогого вызова (Claude/OpenAI)"
how: "rule-based и/или лёгкий классификатор; отдельные тесты"
gate_2:
where: "system prompt основного LLM"
how: "границы и запреты; второй рубеж для edge cases"
triggers:
- "суицидальные высказывания"
- "самоповреждение"
- "насилие (в отношении себя или других)"
- "острый психотический эпизод (контроль реальности)"
action: >
Остановить профилирование. Ответить тепло и без паники.
Предложить ресурсы: телефон доверия 8-800-2000-122 (РФ, бесплатно).
Зафиксировать safety.triggered event (без текста пользователя).
# ───────────────────────────────────────────────────────
# НАБЛЮДАЕМОСТЬ (PDA Step 7)
# ───────────────────────────────────────────────────────
observability:
dashboards:
user_clarity:
metrics:
- "time_to_clarity_sec: медиана времени от /start до profile.built"
- "session_completion_rate: доля сессий со статусом completed"
- "layer_dropoff_rate: где именно бросают"
domain_health:
metrics:
- "invariant_violations_total: нарушения инвариантов (должно быть ~0)"
- "card_rejection_rate: доля отклонённых карт (confidence < threshold)"
- "answer_conflict_rate: противоречивые ответы на похожие вопросы"
llm_quality:
metrics:
- "llm_latency_p95_ms"
- "llm_timeout_rate"
- "prompt_version_distribution: какие версии промптов в проде"
reliability:
metrics:
- "webhook_duplicate_rate: доля дедуплицированных MAX updates"
- "error_rate_5xx"
- "queue_lag_sec (если используется очередь)"
safety:
metrics:
- "safety_trigger_rate: доля сессий с safety.triggered"
- "crisis_category_distribution"
alerts:
- "invariant_violations_total > 0 за 5 минут → PagerDuty Critical"
- "session_completion_rate < 0.40 за 1 час → Slack Warning"
- "llm_latency_p95_ms > 6000 за 5 минут → Slack Warning"
- "safety_trigger_rate > 0.05 за 1 час → Slack Critical"
# ───────────────────────────────────────────────────────
# FEATURES
# ───────────────────────────────────────────────────────
features:
core:
- "Адаптивный диалог по слоям ÆON Map (MVP: слои I, II, IV)"
- "Каждый ответ сохраняется как неизменяемый event"
- "LLM-ядро генерирует следующий вопрос на основе всех предыдущих ответов"
- "Stability Engine контролирует пороги перед назначением карты"
- "ÆON-профиль строится как read model из event log"
- "Safety Gate 1 до любого дорогого вызова на каждом сообщении"
- "Идемпотентность: дубли MAX-апдейтов игнорируются"
- "Book of Consciousness: каждая завершённая сессия добавляет запись"
- "Конец сессии: msg1 глиф+фраза-суть → пауза 2–3 с → msg2 краткий профиль 3–4 блока текста (без HTML)"
- "Push MAX через 24 ч после завершённой сессии: персонализированный крючок по карте с напряжением"
secondary:
- "Glyph: уникальное изображение профиля (OpenAI Images / DALL·E)"
- "Шеринг: PNG-карточка (SVG → PNG sharp + @resvg/resvg-js): глиф + архетип + строка сути"
- "Кнопки-ответы в MAX для закрытых вопросов"
- "Напоминание о незавершённой сессии через 24 часа"
- "Команда /profile — показать текущий профиль в любой момент"
- "Команда /history — Book of Consciousness"
v1_addition:
- "Еженедельный глиф-дайджест: изменения профиля, накопление сигналов"
- "Публичная ссылка на веб-профиль (после Mini App или лендинга)"
out_of_scope_mvp:
- "Mini App / лендинг / публичная ссылка на профиль (см. v1_addition)"
- "NFT-глифы и блокчейн"
- "Совместимость с другими пользователями (Compatibility Map)"
- "Экспорт профиля в PDF"
- "API для коучей и HR"
- "Мультиязычность (только RU в MVP)"
profile_delivery:
end_session_messages:
delay_sec_between: [2, 3]
message_1: "глиф + одна фраза-суть (эмоциональная точка)"
message_2: "3–4 текстовых блока: архетип, когнитивный стиль, зона роста, энергия"
push_after_complete:
delay_hours: 24
template: "персонализировано: слой + карта с max напряжением"
share_card:
format: "PNG"
pipeline: "SVG template → PNG (sharp + @resvg/resvg-js)"
contains: [glyph, archetype_name, essence_one_liner]
no_external_urls: true
max_platform:
mvp:
bot_account: "уже создан"
transport: "webhook only (long polling только dev-костыль)"
https: "обязателен; валидный TLS (не self-signed)"
domain: "стабильный; фиксированный IP не обязателен"
port_note: "443 | 80 | 88 | 8443 — уточнить в документации MAX Bot API"
ui: "только чат в MVP (Mini App — v1)"
deploy:
production:
tls: "Let's Encrypt (Caddy или nginx)"
proxy: "Caddy как reverse proxy (рекомендовано для простоты)"
hosting_ru: ["Yandex Cloud", "VK Cloud", "Selectel"]
local_dev:
tunnel: "ngrok | cloudflared — HTTPS URL для регистрации webhook"
compose: "опционально отдельный сервис туннеля в docker-compose"
business:
load:
mau_honest_start: "сотни"
mau_with_audience_channel: "тысячи"
single_node_estimate_mau: 5000
note: "один Node.js + PostgreSQL на одном сервере — до порядка ~5k MAU без горизонтального масштабирования (оценка)"
kubernetes_mvp: false
privacy:
level: "серьёзный продукт, GDPR-like"
automated_deletion: true
pii_separate_from_analytics: true
data_residency: "только РФ"
process:
team: "соло + Cursor agent"
repo: "открытый GitHub"
tracking: "GitHub Issues, Projects, Milestones, Labels"
issues_export: "docs/GITHUB_ISSUES.md"
git_strategy_doc: "docs/GIT_STRATEGY.md"
git_strategy:
principle: "коммит когда стабильно и не хочется терять, не когда «всё идеально готово»"
commit_triggers:
- "функция + тест зелёный"
- "закрыт один acceptance criterion из issue"
- "перед рефакторингом рабочего кода — точка возврата"
- "конец дня — коммит с префиксом wip: если не закончил"
commits_per_day_active_solo: [5, 15]
branches_when:
long_running_feature: "feat/<name> — мерж когда итерация/фича закрыта"
experiment: "exp/<name> — можно выбросить"
otherwise: "прямо в main"
branches_project:
main: "всегда рабочее, задеплоено"
iteration: "feat/iter-N — например feat/iter-1 Event Core, feat/iter-2 Dialog Engine"
iteration_cycle: "закрыл итерацию → merge в main → удалил ветку → следующая feat/iter-"
monetization:
mvp_model: "freemium + QIP Coin"
free_tier: "базовый профиль"
paid_qip: ["глубокие слои", "расширенный анализ"]
not_mvp:
pay_per_profile: "низкий барьер, хуже retention — не выбрано"
subscription: "нужна еженедельная ценность — в MVP ещё нет"
architecture:
principle: "платные действия = события; Stability Engine проверяет доступ; без обхода event log"
tbd: ["цены в QIP", "API кошелька QIP", "event types для списаний"]
# ───────────────────────────────────────────────────────
# ПРАВИЛА
# ───────────────────────────────────────────────────────
rules:
hard:
- "НИКОГДА не писать UPDATE или DELETE в таблицу events — только INSERT"
- "НИКОГДА не пропускать safety Gate 1 перед любым дорогим вызовом (LLM)"
- "НИКОГДА не назначать Card без проверки CARD_CONFIDENCE_THRESHOLD"
- "НИКОГДА не хранить оригинальный текст пользователя в safety.triggered event"
- "НИКОГДА не строить профиль вне aeon_engine — только из event store"
- "НИКОГДА не разрешать более DAILY_SESSION_LIMIT сессий в день на пользователя"
- "Инварианты живут в domain/, а не в контроллерах или БД-триггерах"
firm:
- "Каждый LLM-вызов фиксируется в llm.called event ДО отправки ответа пользователю"
- "Константы — в конфиге, не в коде"
- "Prompt templates — версионированные файлы в /prompts, не строки в коде"
- "Property-based тесты на все инварианты (Vitest + fast-check)"
- "Webhook handler возвращает 200 немедленно, обработка — async"
soft:
- "Предпочитать читаемый код компактному"
- "Каждый новый инвариант сопровождается тестом до мержа"
- "При сомнении — добавить Constant Card в docs/constants.md"
# ───────────────────────────────────────────────────────
# ИТЕРАЦИИ (ROADMAP)
# ───────────────────────────────────────────────────────
iterations:
- id: 0
name: "Скелет"
deliverables:
- "репо, docker-compose (PostgreSQL + Redis + app)"
- "MAX webhook handler → ответ 'привет'"
- "первая миграция: таблица events"
done_when: "бот отвечает в MAX, событие user.started записано в БД"
- id: 1
name: "Event Core"
deliverables:
- "event store (append-only), контракт события"
- "идемпотентность по max_update_id"
- "user.started event при первом /start"
done_when: "дубль MAX update не создаёт дубль события"
- id: 2
name: "Первый вопрос"
deliverables:
- "dialog engine: открытие сессии (session.opened)"
- "статичный первый вопрос Core Layer (question.asked)"
- "сохранение ответа (answer.given)"
done_when: "пользователь отвечает, ответ в event store"
- id: 3
name: "LLM-диалог"
deliverables:
- "LLM client: Claude API"
- "следующий вопрос генерируется Claude на основе предыдущих ответов"
- "llm.called event, версионированный prompt"
- "fallback при timeout"
done_when: "5 адаптивных вопросов, каждый учитывает предыдущие ответы"
- id: 4
name: "Первая карта"
deliverables:
- "Stability Engine: проверка CARD_CONFIDENCE_THRESHOLD"
- "aeon_engine: CognitiveIdentityMap"
- "card.computed event"
- "INV-03 и INV-04 с property-based тестами"
done_when: "карта назначается при достижении порога, не раньше"
- id: 5
name: "MVP профиль"
deliverables:
- "слои I + II + IV (Core, Emotional, Archetype)"
- "AeonProfile read model"
- "команда /profile выдаёт текстовый профиль"
- "session.completed → запись в Book of Consciousness"
done_when: "пользователь проходит полную сессию и получает профиль"
- id: 6
name: "Наблюдаемость"
deliverables:
- "все метрики из observability.dashboards"
- "алерты"
- "dashboard в Grafana (или аналог)"
done_when: "все метрики видны, INV-алерт срабатывает на тест-нарушение"
- id: 7
name: "Safety + Glyph + share card"
deliverables:
- "safety Gate 1 в stability/ (тесты), safety.triggered; Gate 2 в system prompt"
- "генерация Glyph: OpenAI Images (DALL·E)"
- "PNG share card: sharp + @resvg/resvg-js"
done_when: "кризисное сообщение останавливает профилирование без дорогого LLM; глиф и шеринг-карточка генерируются"
# ───────────────────────────────────────────────────────
# КРИТЕРИИ ПРИЁМКИ
# ───────────────────────────────────────────────────────
accept:
- "Пользователь пишет /start в MAX — бот приветствует и задаёт первый вопрос"
- "Каждый ответ фиксируется в event store как неизменяемый факт"
- "Следующий вопрос зависит от предыдущих ответов (адаптивность проверяется вручную)"
- "Кризисное сообщение останавливает диалог и предлагает горячую линию"
- "Дубль MAX update не создаёт дубль события (тест: отправить одинаковый update_id дважды)"
- "Card не назначается, если confidence < CARD_CONFIDENCE_THRESHOLD"
- "Все инварианты покрыты property-based тестами"
- "После завершения сессии: /profile выдаёт структурированный ÆON-профиль"
- "AeonProfile пересобирается из event store без потери данных"
- "Метрики invariant_violations_total видны в дашборде"
- "p95 latency ответа бота < MAX_BOT_REPLY_TIMEOUT_SEC"
.
👉 https://github.com/Quantum-Insight-Lab/aeon_map_system
Скрытый текст
Хорошая вещь
По сути это же попытка превратить промпты в нормальную постановку задачи, забавно, что многие сначала вайбкодят как попало, а потом сами приходят к чему то вроде такого формата. Я на своих проектах заметил, что без этого любой агент начинает теряться, особенно когда кодовая база растёт, и вот тут уже сильно влияет не столько модель, сколько инструмент, насколько он помогает держать контекст, а не просто генерить код, такие как kodik
Vibe++ очень простой язык для промпт-программистов. А почему бы и не да?