Skip to content

Repository files navigation

🧠 NeuroBox🤖

🏠 Главное

🧠 Сервис управления агентами. Клонируется на любой машине, поднимается в докере парой команд, настраивается конфигом. 🧩 Агент здесь не монолит, а сборка трёх заявленных вещей: паспорт — кто он, рецепт — с чем работает, сессия — живой прогон с историей и владельцем. 🪶 Тяжесть (инструменты, браузеры, доменные знания) живёт снаружи, за 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 src

Note

Прогоны исполняются в процессе сервиса. Очередь и отдельный воркер приезжают своей фазой; сегодня это заявлено, а не спрятано — оборванные рестартом прогоны закрываются с причиной, а не висят в «работает».

📚 Документация

Документация в этом репозитории — не побочный продукт, а часть архитектуры: у неё свои понятия, свои правила и свой шаблон оформления, ровно как у любого другого механизма.

🧠 Концепции

Дока — от кода, не наоборот. Дока по большей части — проза агента, написанная ПОСЛЕ и ПО архитектуре уже существующего кода. Не «сперва спецификация, потом реализация по ней» — код, паспорт, тесты уже решают устройство; агент читает их и пересказывает человеку словами, а не придумывает архитектуру из текста дока. Разошлись — прав код. Обновление дока это ЧТЕНИЕ актуального кода заново, не правка старого текста по памяти.

📐 Основание — единственное исключение, и оно временное. Пока кода нет, описывать нечего, и 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

🧷 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 (план) — трейсы прогонов и отладка.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages