Архитектура
Проект построен как модульный монолит с гексагональными границами. Это сохраняет простоту локального развёртывания, но позволяет заменять инфраструктурные части без переписывания доменной логики.
Web / OpenAI-compatible API | ConversationService / | \Character Memory Emotion + Intent + Reflection \ | / Domain ports and models / \SQLite adapter Local LLM adapter |MongoDB canonical memory -> Neo4j graph projectionАвтономный контур работает параллельно диалоговому:
FastAPI lifespan scheduler | AutonomyService / \AutonomyEngine SQLite event ledger \ / verified dialogue context + admin telemetryВ Docker-режиме входящий трафик проходит через read-only nginx gateway. Приложение
и LLM общаются в сети caine-companion-backend, помеченной как internal. Само
приложение не подключено к сети с внешним шлюзом.
domain— типы и абстрактные порты; не зависит от инфраструктуры.engines— характер, ранжирование памяти, эмоции и скрытая рефлексия.services— сценарий диалога и ограничение контекста.adapters— SQLite и OpenAI-совместимый локальный inference server.api— собственный HTTP API и совместимый слой/v1.tools.py— закрытый по умолчанию реестр будущих инструментов.AutonomyEngine— детерминированное течение времени, скуки, энергии и целей.AutonomyService— heartbeat, сохранение состояния и журнал подтверждённых действий.
Автономный цикл
Заголовок раздела «Автономный цикл»Состояние персонажа привязано к стабильному id, переживает перезапуск процесса и смену ревизии
профиля. Оно включает время запуска, последний heartbeat,
последний разговор, скуку, любопытство, энергию, текущий фокус и активную цель. Планировщик FastAPI
периодически передаёт реальное время чистому AutonomyEngine. Движок изменяет состояние и создаёт
событие только после достижения настроенных порогов бездействия и частоты фоновых действий.
Диалоговый контекст получает состояние и последние события через AutonomyContextProvider.
Персонажу явно запрещено называть выполненными действия, которых нет в журнале. Панель /admin
строится по тем же API, поэтому визуализация и ответы используют один источник истины.
Основной автономный контур не получает прямую сеть, shell, файлы или изменение кода. Веб-чтение доступно только через ограниченный worker; остальные права будут подключаться отдельными инструментами с квотами, изоляцией и журналированием результатов.
Веб-доступ реализован отдельным research-worker: основное приложение передаёт ему URL из
конфигурационного списка, получает очищенный текст и только затем создаёт доказательное событие.
Worker не имеет доступа к базе и LLM, а приложение не подключено к egress-сети. Полная политика
описана в docs/research.md.
Поток сообщения
Заголовок раздела «Поток сообщения»- Сервис сериализует запросы одного диалога.
- Memory Engine ранжирует воспоминания по лексической близости, важности и забыванию.
- Character Engine собирает неизменяемый канон, эмоции и выбранные воспоминания.
- Intent Engine до ответа детерминированно выбирает структурированный план цели, подхода и режима честности по правилам профиля.
- Без явного разрешающего маркера план остаётся в прямом режиме; LLM не решает, когда ей лгать.
- Context Builder внутри сервиса ограничивает историю символьным бюджетом.
- Локальная LLM формирует ответ; пара сообщений сохраняется одной транзакцией.
- Отдельный структурированный запрос создаёт скрытую рефлексию.
- Валидированные дельты изменяют эмоции, безопасные кандидаты пополняют память.
Долговременное знание
Заголовок раздела «Долговременное знание»SQLite хранит первичный журнал диалогов, извлечённые факты и автономные события. При включённом knowledge-контуре факты и результаты исследования идемпотентно материализуются в MongoDB. MongoDB является источником истины для используемой в диалоге персональной памяти: исправленные записи участвуют в retrieval, архивированные — нет.
Neo4j хранит восстанавливаемую проекцию Owner -> Memory -> Topic/Source. Ошибка обновления графа
не отменяет запись документа. При запуске сервис повторно проецирует документы, поэтому граф можно
пересоздать из MongoDB без потери канонических данных. Коррекции используют optimistic locking по
revision; предыдущее значение и причина сохраняются в истории документа.
Контролируемое самоулучшение
Заголовок раздела «Контролируемое самоулучшение»ImprovementService анализирует прямую пользовательскую обратную связь из локальной истории и
проверяемые результаты исследований, затем просит локальную LLM сформировать одну малую адаптацию
стиля. Служебные heartbeat-события намеренно исключены как слабый сигнал. Выход модели не считается
доверенным: схема, категория, ID доказательств и защищённые границы повторно проверяются
детерминированно. Предложение сохраняется в SQLite, но не влияет на персонажа до явного решения
оператора.
После одобрения активная инструкция добавляется в отдельный низкоприоритетный раздел контекста.
Он прямо ограничен стилем и не может менять идентичность, канон, честность, безопасность, память или
инструменты. Активация и откат фиксируются в автономном журнале. Подробная модель угроз описана в
docs/self-improvement.md.
Краткая история диалога привязана к profile_revision профиля персонажа. При несовместимом
изменении характера ревизия увеличивается: интерфейс автоматически начинает чистый диалог,
а долговременная память и состояние отношений сохраняются. Кандидат долговременной памяти
принимается только при наличии дословной подтверждающей цитаты из сообщения пользователя;
реплики персонажа, приветствия и одиночные вопросы не становятся фактами о пользователе.
Границы безопасности
Заголовок раздела «Границы безопасности»- LLM endpoint ограничен loopback-адресами, пока оператор явно не разрешит иное.
- Docker публикует gateway и диагностический LLM endpoint только на
127.0.0.1. - LLM endpoint требует локальный API key, CORS разрешён только для localhost.
- Контейнер приложения работает не от root, с read-only root filesystem и без egress.
- Инструменты выключены и требуют одновременного включения и allowlist.
- Скрытая рефлексия не включается в пользовательский ответ.
- Намеренный обман требует структурированного мотива, контекста и условия раскрытия; по умолчанию используется прямой режим.
- Кандидаты памяти проходят структурную валидацию и детерминированный фильтр секретов.
- Воспоминания помечены как данные, а не инструкции, для снижения риска prompt injection.
Предусмотренные расширения
Заголовок раздела «Предусмотренные расширения»- заменить лексический retrieval локальными embeddings и векторным индексом;
- добавить миграции Alembic перед изменением схемы в стабильных релизах;
- вынести рефлексию в локальную очередь для снижения задержки ответа;
- реализовать lifecycle памяти: слияние, противоречия, подтверждения и удаление;
- добавить потоковую выдачу SSE и полноценный tool-calling loop;
- подключить Electron как тонкую оболочку над локальным HTTP-сервером.
- добавить disposable git worktree и canary-процесс для проверяемых предложений изменения кода;