Статьи об архитектуре обычно описывают целевое состояние и умалчивают, какая его часть существует. Читатель принимает описание за реальность и обнаруживает расхождение при первом использовании.
Поэтому здесь у каждой части стоит отметка статуса: работает, частично или проект. «Проект» означает, что это записано в нашем внутреннем документе и не реализовано в коде. Отметки расставлены по состоянию кода на 25.08.2026.
И сразу то, что стоит знать до чтения: репозиторий Persona закрыт, публичной лицензии нет. Аргумент «прочитайте код и проверьте» здесь не работает, поэтому ниже даны имена конкретных файлов и модулей — не как доказательство, а как опора для будущей проверки, если код когда-нибудь откроется.
Отдельно про название. В нашей внутренней документации агентная архитектура фигурирует под именем Hermes. Это создало путаницу, которую мы разбираем отдельно: Persona не использует ни модели Nous Hermes, ни фреймворк Hermes Agent — слово встречается в коде только в комментариях как ссылка на чужие идеи. Разбор трёх значений — в материале про три разные вещи под именем Hermes.
#Основная идея
Одно ядро, много входов. Не отдельный бот для мессенджера и отдельный код для сайта, а один обработчик хода, к которому ведут разные адаптеры. Идентичность одна, память одна, набор правил один.
Причина не в красоте. Два независимых пути обработки хода расходятся в поведении через месяц после написания, и расхождение обнаруживается там, где его труднее всего заметить: в правах на инструменты и в том, что попадает в память.
#Схема ядра
ВХОДЫ ЯДРО ВЫХОДЫ
веб / SSE ────┐ ┌──▶ поток событий
│ │ в интерфейс
Telegram ─────┼──▶ ConversationService ──────────┤
│ handle_turn / stream_turn │
фоновая ──────┘ │ └──▶ доставка
задача │ в мессенджер
├─ политика доступа
├─ разрешение сессии
├─ сборка контекста
├─ цикл модель ↔ инструменты
├─ сохранение сообщений
└─ пост-обработка хода
│
┌───────────────────┼───────────────────┐
▼ ▼ ▼
ПАМЯТЬ ФАКТОВ ЖУРНАЛ ИСТОРИИ ГРАФ
user_memory chat_message kg_entity/kg_edge
Статус: частично. Ядро существует — это класс ConversationService в app/application/chat/service.py, с портами для хранилища, контекста, модели, инструментов и пост-обработки. Через него ходят Telegram и часть веб-запросов.
Но не все. В веб-маршруте есть развилка: расширенный режим чата обрабатывается собственным потоковым кодом в app/web/routes/chat_sessions.py, со своим циклом вызова инструментов, а через общее ядро идут ходы при выключенном расширенном режиме. То есть путей обработки сегодня два, и обещанное «одно ядро на все поверхности» верно наполовину. Это известный долг, а не задумка.
#Инварианты
Список правил, которые не должны нарушаться ни при каких настройках. Для каждого — статус и место в коде.
1. Инструменты доступны только владельцу инстанса. Статус: работает. Проверяется на обоих входах в чат: в расширенном режиме условие включает и владельца, и характер запроса; в пути через общее ядро — отдельная проверка актора. У не-владельца список инструментов пуст, а политика инструментов отсутствует.
2. Автономно модель вызывает только читающие инструменты. Статус: работает. Классификация в app/mcp/tool_policy.py, отбор — функция, пропускающая исключительно класс read_only. Новый или внешний инструмент по умолчанию получает класс «неизвестно» и автономии не получает.
3. В групповых чатах доступен ровно один инструмент. Статус: работает. Поиск в сети, и только он — app/integrations/telegram/tool_policy.py. Не «все читающие»: универсальный HTTP-инструмент принимает произвольные заголовки и тело, а прямое открытие страницы обходит проверку адреса.
4. Действия класса «выполнение» и «разрушение» из мессенджера требуют подтверждения. Статус: работает. Такой вызов не исполняется, а паркуется и отвечает карточкой с кнопками; имя инструмента и аргументы перечитываются из записи в базе, а не из нажатия. Если подтверждать негде — отказ, а не выполнение.
5. Цикл самостоятельных размышлений не пишет в память. Статус: работает, причём структурно: в пакете app/thinking/ вообще нет пути записи в user_memory или другие таблицы памяти, и это закреплено отдельным тестом, а не соглашением.
6. Ночная обработка памяти не меняет память напрямую. Статус: работает. Цикл в app/chat/reflection.py работает по схеме «предложение, а не запись»: кандидаты и доказательства сначала фиксируются в журнале, затем отдельная детерминированная политика решает, что применить. Модель никогда не исполняет изменение памяти сама.
7. Проактивное сообщение строится только на данных владельца. Статус: работает. Политика в app/domains/autowake/policy.py пропускает три класса происхождения — сказанное владельцем, его приватные данные и выводы из них; групповое и внешнее отклоняется, текст, похожий на секрет, отсеивается по набору образцов до записи сообщения.
8. Один входящий апдейт мессенджера обрабатывается не более одного раза. Статус: работает, через пометку обработки по номеру обновления.
9. Раздельные ленты при общей памяти. Статус: частично. Сессии разделены, память привязана к пользователю. При этом данные захвата экрана и звука остаются глобальными и однопользовательскими.
10. Любое изменение памяти обратимо и видно владельцу. Статус: частично. Ночной цикл ведёт журнал ревизий с доказательствами; сквозной интерфейс «почему агент это помнит» с откатом одним действием — проект.
#Что работает сегодня
Единый обработчик хода — частично, как описано выше.
Классификация инструментов по риску и автономия только для чтения — работает. Пять классов плюс «неизвестно», отбор по классу, перечитывание списка разрешённых имён перед каждым побочным эффектом, а не снимком на начало хода.
Пределы хода — работают: не более шести раундов цикла (восьми в углублённом режиме), не более шестнадцати вызовов, до 4000 символов на результат и 24000 суммарно, дедупликация повторных вызовов по точному тексту.
Telegram как полноценная поверхность — работает: allowlist по числовому идентификатору владельца и отдельный список групп, дедупликация обновлений, подтверждения на опасные вызовы. Как это устроено — в руководстве по агенту в Telegram.
Цикл самостоятельных размышлений — работает и выключен по умолчанию. Право писать в чат — отдельный выключатель, тоже выключенный. Есть предел шагов, суточный бюджет, требование доказательств для тем, которые делают утверждения о владельце, и разметка каждой записи как наблюдения либо догадки.
Ночная консолидация памяти — работает и включается вручную: соответствующий ключ по умолчанию выключен. Цикл предлагает, а не записывает; подробности и публичное исправление нашей же ошибки в описании этого механизма — в материале про ночную консолидацию памяти.
Граф знаний — работает как проекция поверх фактов; разбор — в материале про граф памяти.
Проактивные сообщения — работают с ограничителями: пауза два часа, не более четырёх сообщений в сутки, тихие часы с 23:00 до 8:00 с переносом, а не выбрасыванием.
#Что сделано наполовину
Одно ядро на все поверхности. Два пути обработки вместо одного.
Провенанс доказательств. Ночной цикл связывает кандидатов с источниками, но для текста с экрана и расшифровки речи происхождение прослеживается хуже, чем для сообщений чата: там есть идентификатор сообщения, здесь — нет полноценной ссылки на фрагмент. Почему это важно — в материале про то, зачем нужен провенанс в памяти.
Разграничение между пользователями. Это список разрешённых путей плюс пользовательские настройки на кодовой базе, которая начиналась однопользовательской. Усиленной мульти-тенантной границей это не является, и называть это так было бы неправдой.
Обратимость изменений памяти. Журнал ревизий есть, интерфейс отката — нет.
#Что остаётся проектом
Здесь перечислено то, что записано в нашем внутреннем документе и не реализовано. Документ имеет статус предложения и кода не меняет.
- Разделение на слои предметной области, приложения, портов и инфраструктуры с запретом на обращение к базе из обработчиков маршрутов.
- Отдельные сущности журнала событий, входящей очереди и очереди доставки с гарантией «хотя бы один раз» и переживанием перезапуска.
- Устойчивый планировщик с арендой задач, единой таблицей заданий, группами параллелизма и неизменяемым журналом исполнений вместо разрозненных фоновых задач.
- Разбор кандидата в память с проверкой следования из доказательства, оценкой качества поиска до и после и откатом прогона целиком.
- Граф с псевдонимами сущностей, временными интервалами и силой связи как функцией независимых доказательств, а не числа повторов вывода модели.
- Сквозной интерфейс «почему агент это помнит или сделал» со ссылками на доказательства.
Список длинный, и это нормально для проектного документа. Ненормально было бы выдавать его за описание работающей системы.
#Честные ограничения
Раздел, без которого остальное было бы рекламой.
Модель подключает пользователь. Persona не поставляет модель и не проксирует запросы. Либо ваша Ollama — тогда переписка не уходит наружу, либо ключ облачного провайдера — тогда текст запросов уходит именно этому провайдеру. Участник без ключа не получает ответов вовсе.
Ключи участников хранятся в открытом виде. Ключ пишется в таблицу пользовательских настроек без шифрования.
Захват экрана и звука, таймлайн, поиск, заметки, напоминания, дашборды, Telegram и брифинг доступны только владельцу инстанса. Участники получают чат, память, граф, голос, навыки и свой характер. Мульти-тенантного захвата нет.
Захват не работает в контейнере — нет графической сессии.
На размещённой версии стоит Яндекс.Метрика с вебвизором, на публичных страницах и в интерфейсе. При развёртывании у себя счётчика нет: это один подключаемый шаблон.
Локальная небольшая модель слабее топовой облачной в сложных рассуждениях. Наше преимущество — память о вашем контексте и контроль над данными, а не «сырой» интеллект.
#Чем это отличается от чужих решений
Коротко: источниками памяти. Зрелые агентные фреймворки строят память из напечатанного — из того, что попало в разговор. Наша ставка — события реальной жизни: текст с экрана, расшифровка речи, календарь, заметки. Это даёт материал, которого нет у собеседника по переписке, и создаёт проблемы, которых у него тоже нет: происхождение фрагмента прослеживается хуже, говорящего надо ещё определить, а чужая реплика не должна становиться фактом о вас.
Развёрнутое сравнение, включая раздел о том, где сторонний фреймворк объективно лучше нас, — в материале Persona Agent и Hermes Agent.
#Частые вопросы
#Persona построена на Hermes?
Нет. Ни модели Nous Hermes, ни фреймворк Hermes Agent в Persona не используются и не подключены. Имя Hermes встречается в нашем коде исключительно в комментариях — как ссылка на чужие идеи, которые мы читали. Внутреннее название архитектуры совпало с чужими продуктами, и это наша ошибка в именовании, а не интеграция.
#Что из описанного реально работает?
Классификация инструментов по риску с автономией только для чтения, ограничение групповой поверхности одним инструментом, подтверждения на опасные вызовы, пределы хода, Telegram с allowlist и дедупликацией, цикл размышлений без права записи в память и ночная консолидация в режиме предложений. Единое ядро — наполовину: путей обработки хода сегодня два.
#Ассистент сам себе что-то думает по ночам?
Только если вы это включили: и цикл размышлений, и ночная консолидация памяти по умолчанию выключены. Даже включённый цикл размышлений не может писать в память — в его коде физически нет такого пути, и это закреплено тестом.
#Может ли агент выполнить команду без моего ведома?
Инструменты доступны только владельцу инстанса, автономно модель вызывает лишь читающие, а вызовы, которые выполняют код или удаляют данные, приходя из мессенджера, паркуются за одноразовым подтверждением. При отсутствии канала подтверждения действие не выполняется.
#Данные остаются на моей машине?
Если Persona развёрнута у вас и подключена локальная Ollama — переписка остаётся на вашей машине. Если подключён ключ облачного провайдера, текст запросов уходит этому провайдеру. На размещённой версии данные лежат на её сервере, и там же работает Метрика с вебвизором.
#Почему так много помечено как проект?
Потому что внутренний документ описывает целевое состояние, а статья — текущее. Смешивать их означало бы обещать функции, которых нет. Мы предпочитаем длинный список «проект» короткому списку недовольных пользователей.
#Вывод
Работающая часть архитектуры — это политика прав на инструменты, пределы хода, Telegram с раздельными списками доступа и два фоновых механизма, оба выключенных по умолчанию и оба лишённых права писать в память напрямую.
Незакрытые долги — второй путь обработки хода в вебе, неполный провенанс для экрана и звука, отсутствие интерфейса отката и разграничение пользователей, которое не является усиленной границей. Если вы выбираете инструмент под многопользовательский сценарий с захватом — это не наш случай сегодня, и лучше знать об этом отсюда.