- 🏠 Главное
- 🚀 Запуск
- 📚 Документация
- 🗃️ Базовые понятия сущности
- 🧬 Модель
- 🎚️ Слои конфигурации
- 🔌 MCP
- 🧱 Устройство
- 🛠️ Инструменты
- ❓ FAQ
- 🗺️ ROADMAP
- ⏸️ CHECKPOINT — где мы сейчас и что дальше
- ⚖️ WEIGHT — журнал замеров: сколько контекста съедают MCP-серверы
🧠 Сервис управления агентами. Клонируется на любой машине, поднимается в докере парой команд, настраивается конфигом. 🧩 Агент здесь не монолит, а сборка трёх заявленных вещей: паспорт — кто он, рецепт — с чем работает, сессия — живой прогон с историей и владельцем. 🪶 Тяжесть (инструменты, браузеры, доменные знания) живёт снаружи, за MCP; сам рантайм тонкий и говорит только по http.
Note
Что уже работает: запуск в докере, каталог паспортов/семян/рецептов из файлового слоя,
опрос MCP-серверов, сверка семени с паспортом, развёртка рецепта и A2A-агент над локальным
Claude Code, сессии с историей и учётом расхода, поток событий с отменой, веб-пульт.
Чего ещё нет: ролей и квот, очереди с отдельным воркером. Единственный источник правды о готовности — ROADMAP.yaml:
не построено сегодня, значит не заявлено здесь.
Две команды на любой машине, где есть докер:
cp .env.example .env
docker compose up✅ Готово: пульт на http://127.0.0.1:3100, ручки сервиса — на
http://127.0.0.1:8000/docs. Погасить — docker compose down.
Important
Правка .env сама по себе до контейнера НЕ доезжает — переменные читаются при его создании.
После неё нужен docker compose up -d --force-recreate. Файлы в config/ так вести себя не
будут: они примонтированы и перечитываются на каждый запрос.
То же самое плюс одна строка в .env:
ENVIRONMENT=production
ACCESS_TOKEN=<свой; openssl rand -hex 24>Без токена вне разработки сервис НЕ поднимается и говорит почему — иначе однажды встанет
открытым, и заметят это не свои. Запрос обязан назвать и токен, и логин — заголовками
Authorization: Bearer <токен> и X-User-Login: <логин>; без любого из двух — 401. Токен
отвечает «можно ли сюда вообще», логин — «чьим именем»: сессии живут по владельцам, и у каждого
логина свой агент. Логин — опознание, а не вход: проверить его нечем до общего модуля
авторизации, и это названо честно, а круг тех, кто может назваться, ограничен токеном. Наружу порты не публикуются вовсе: пульт и ручки слушают петлю,
а снаружи к ним ходят через вход машины — отдельный репозиторий Gate,
который держит TLS и знает карту соседей. Публикуй мы порт наружу — рядом со входом появилась бы
вторая дорога, без TLS.
🚢 Обновить машину — одной командой с ноутбука, .\ship.ps1 [службы] [-NoBuild]: она пушит
незапушенное здесь и во входе, а на машине ship.sh делает git pull обоих репозиториев,
сборку, подъём и проверяет каждого соседа живым запросом. На машине ничего не правится руками —
только то, что уже стало файлом в репозитории. Витрине, поднятой у разработчика на ноутбуке,
ходить в ручки боевого бокса разрешает CORS_ORIGINS в .env — точные источники, не *.
🧰 Разработка без контейнера — только для быстрой обратной связи, ничего не обещает и заменой докеру не является:
cd neurobox
uv sync
uv run pytest && uv run ruff check . && uv run mypy srcNote
Прогоны исполняются в процессе сервиса. Очередь и отдельный воркер приезжают своей фазой; сегодня это заявлено, а не спрятано — оборванные рестартом прогоны закрываются с причиной, а не висят в «работает».
Документация в этом репозитории — не побочный продукт, а часть архитектуры: у неё свои понятия, свои правила и свой шаблон оформления, ровно как у любого другого механизма.
Дока — от кода, не наоборот. Дока по большей части — проза агента, написанная ПОСЛЕ и ПО архитектуре уже существующего кода. Не «сперва спецификация, потом реализация по ней» — код, паспорт, тесты уже решают устройство; агент читает их и пересказывает человеку словами, а не придумывает архитектуру из текста дока. Разошлись — прав код. Обновление дока это ЧТЕНИЕ актуального кода заново, не правка старого текста по памяти.
📐 Основание — единственное исключение, и оно временное. Пока кода нет, описывать нечего, и README держит не устройство, а решения: словарь, границы, канон. Как только появляется первый рабочий кусок, правило вступает в полную силу — раздел про него переписывается ЧТЕНИЕМ этого куска, а не редактурой того, что здесь написано авансом.
Словарь общий с фреймворком. NeuroBox и фреймворк идут под одним брендом и говорят одними словами. Смысл термина закреплён один раз; у каждой сущности он раскрывается в СВОЁМ контексте, но не переизобретается заново под другим словом с тем же смыслом. 🔍 Появился соблазн назвать рецепт «пресетом», а семя «блоком» — это ошибка, а не находка.
Цепочка документации — по слоям, снизу вверх. Верхний слой описывает работу с нижним ТОЛЬКО ссылкой на его доку, не пересказывая её своими словами. Нижний слой про верхние не знает вообще ничего — он не может знать заранее, кто и как его будет использовать.
Тройка — в корне любого скоупа. README.md/FAQ.md/ROADMAP.yaml — обязанность любой папки,
которая является границей по смыслу, а не просто техническим сложением файлов. 🔍 Внятность этой
доки — диагностика самой композиции: если содержимое папки не удаётся описать одним связным
текстом, проблема в границе, а не в доке.
Обоснования — в FAQ.md, не в README. README держит факты и примеры; FAQ отвечает,
почему так, а не иначе, и что уже проверено на практике.
Никаких номеров и ссылок на тикеты — ни в README, ни в FAQ, ни в ROADMAP. Трекер меняется, тикеты закрываются, а читатель прав на него может и не иметь. Причина пишется своими словами.
В коде — не проза. Простыня объяснения рядом с кодом запрещена: обоснование живёт в FAQ.md,
комментарий в коде — максимум короткая пометка и ссылка на страницу дока.
Не проверено сегодня — не заявлено. Голословных «держит проба X» в доке нет. Снятая проверка снимается вместе со своим утверждением, а не остаётся висеть текстом.
Любая сущность — сервис целиком, отдельный движок, отдельная функция — описывает себя одним и тем же небольшим набором понятий. Набор общий с фреймворком; ниже то, как каждое читается ЗДЕСЬ.
Первые пять — то, что сущность заявляет о себе ДЕКЛАРАТИВНО, данными:
- Анатомия — именованный список частей, каждая со своим устойчивым адресом. Нужна, чтобы что угодно снаружи (пульт, инструмент, другой сервис) сослалось на конкретный кусок по имени, а не гадало по порядку.
- Паспорт — то, что сущность заявляет о себе как данные. У агента это его природа: провайдер, модель, лимиты, семплинг. У MCP-сервера паспорт свой, и он ВЫЧИТЫВАЕТСЯ у самого сервера, а не пишется у нас руками.
- ИО — контракт данных: что принимается на входе и что реально отдаётся на выходе. Форма данных, зафиксированная один раз и переиспользуемая всем, что с сущностью соединяется.
- Настройки — именованные переключатели, у каждого из которых есть настоящий двойник в самой сущности, а не воображаемый список того, что «неплохо бы» уметь.
- Состояния — здесь это именованные отказы: сервер не поднялся, ключа нет, лимит выбран, тулза отвергла. Отказ возвращается ЗНАЧЕНИЕМ с конкретным именем, а не исключением — по этому имени пульт объясняет человеку, что случилось.
Последние два — не декларация, а ДОКАЗАТЕЛЬСТВО, что декларация работает:
- Сборки — прогнанные примеры того, как части реально складываются в рабочую композицию через настоящий механизм. Не иллюстрации в доке.
- Рецепт — конкретное воплощение, живущее СНАРУЖИ самой сущности. У движка это его плагины, съёмный слой, который сущность не носит в себе. У агента — набор семян, с которыми он работает.
🧩 Четыре сущности: три именованные переиспользуемые и одна живая.
| Сущность | Что это | Пример |
|---|---|---|
| Паспорт | КТО агент: провайдер, модель, лимиты, семплинг | клод-опус-5, локалка-qwen |
| Семя | минимальный именованный вход, разворачивающийся во много | windshift, solidjs, дока |
| Рецепт | С ЧЕМ работает: комбинация семян | фронт-разработка |
| Сессия | живой экземпляр: паспорт + рецепт + история + владелец | — |
🌱 Семя названо семенем не для красоты: одна строка адреса windshift разворачивается в десятки
тулзов с инструкцией — ровно как одно семя цвета даёт всю половину шкалы. Минимальный вход,
порождающий много.
🍲 Рецепт — комбинация семян, и ничего кроме. Поэтому «вынести повторяющееся в дефолты» это операция над СЕМЕНЕМ: переносим семя слоем ниже, а рецепты ссылаются на него по имени и ничего не замечают.
Паспорта, семена и рецепты живут в трёх слоях. Каждый следующий перекрывает предыдущий.
| Слой | Где | Что держит |
|---|---|---|
| 0️⃣ Образ | запечено в докер | эталонные наборы: «эталон монорепо», «эталон MCP-сервера» |
| 1️⃣ Файл | в репозитории | личные стандарты; лежат в гите и ездят везде |
| 2️⃣ База | Postgres | динамика: создаётся из пульта и API у конкретной установки |
🚫 Автосинка база → файл запрещена. Промоушен — осознанный экспорт семени слоем ниже, дальше коммит руками. Иначе гит шумит сам по себе, и непонятно, кто автор изменения.
🔎 Источник виден всегда. У каждого элемента в API и в пульте есть метка, из какого он слоя. Три слоя без этого превращаются в гадание, откуда взялось значение.
🧷 MCP не вшивается. Сервер — это адрес и токен, а не код внутри сервиса.
{
"mcpServers": {
"windshift": {
"type": "http",
"url": "http://10.8.1.3:8095/mcp",
"headers": { "Authorization": "Bearer ${WINDSHIFT_TOKEN}" }
},
"ark-ui": { "command": "npx", "args": ["-y", "@ark-ui/mcp"] }
}
}🔐 Секреты только через ${VAR} из окружения. Токенов в файле нет никогда. Нет переменной —
сервер не поднимается, и это заметная поломка, а не тихая.
🛰️ Канон транспорта — http. Серверы stdio живут в САЙДКАРЕ: отдельный контейнер, где стоят
node, браузер и всё остальное, что им нужно. Рантайм остаётся тонким и одинаковым у всех, а
упавший сервер не роняет сессии. Кому нужно иначе — свой Dockerfile поверх базового.
📇 Паспорт сервера вычитывается. При подключении сервер опрашивается, перечень тулзов и инструкция сохраняются. Отсюда две вещи: в пульте видно, что сервер даёт, и «прописан, но не отвечает» ловится в момент подключения, а не в середине работы за потраченные токены.
Note
Раздел описывает решённую раскладку, а не существующий код. Статус каждой части — в
ROADMAP.yaml.
🗂️ Зоны репозитория. Каждая — граница по смыслу, и у каждой своя тройка доков.
| Зона | Что это |
|---|---|
neurobox/ |
сам сервис: HTTP, агентский цикл, база. Тонкий по построению |
config/ |
файловый слой конфигурации — твои стандарты, лежат в гите |
sidecar/ |
A2A-агент над Claude Code и чужое тяжёлое окружение |
console/ |
пульт; потребитель API, не совладелец логики |
🚪 Вход машины сюда не входит. TLS, порты и карта соседей живут в отдельном репозитории Gate: он свойство машины, а не часть продукта. Владей им бокс — он отвечал бы за доступность соседей, которые ему не принадлежат.
🐳 Контейнеры. compose.yaml в корне — единственный поддерживаемый способ запуска.
| Контейнер | Назначение |
|---|---|
api |
HTTP-поверхность: сессии, рецепты, семена, паспорта, стрим по SSE |
worker |
долгие прогоны; сессия думает минутами, запросом это не держится |
postgres |
сессии, история, владельцы, расход токенов, динамический слой конфига |
redis |
очередь воркера и шина стрима в пульт |
claude |
A2A-агент над локальным Claude Code; stdio-серверы позже сюда же |
console |
пульт; он же отдаёт сервис по одному с собой адресу |
🐍 Сервис
- FastAPI — HTTP-поверхность; скелет продуктового репозитория берётся готовым, не пишется свой.
- MCP SDK — свои серверы бокса и опрос чужих.
- A2A — общий канал до агентов. Агентский цикл живёт в рантайме за этим каналом, а не здесь: сервис остаётся тонким и про устройство агента не знает.
- uv — тулчейн и локфайл.
План, ещё не в коде — появится вместе с задачей, которая этого потребует:
- Pydantic AI — свой агентский цикл для провайдеров, у которых нет собственного рантайма.
- LiteLLM — слой провайдеров: ключ OpenAI и локальная модель одним кодом.
🗄️ Состояние
- PostgreSQL — единственное хранилище состояния.
- Alembic — миграции.
- Redis (план) — очередь долгих прогонов и шина стрима. Сегодня прогоны идут в процессе сервиса, и это заявлено, а не спрятано.
🐳 Контейнер
- Docker Compose — единственный способ запуска: клон, конфиг, две команды.
- Dev Containers — девбокс поднимается стандартным образом, без самописных скриптов поверх.
📈 Наблюдаемость
- Логи с идентификатором запроса и таймингами — есть.
- Учёт расхода (токены, кэш, стоимость, длительность) ведётся в СВОЕЙ базе: квоты и роли наша ответственность, а не внешнего сервиса. Есть.
- Langfuse (план) — трейсы прогонов и отладка.