Cairn — движок поиска решений по графу фактов для AI-агентов
📂 Исходный код на GitHubДвижок общего назначения для поиска пути в пространстве состояний: граф фактов и намерений, цикл OODA у воркеров, сервер и диспетчер, поддержка Claude Code, Codex и Pi, запуск в Docker или локально без него. Python, лицензия AGPL-3.0.
Cairn — движок поиска решений по графу фактов
Cairn — это движок решения задач, в котором нет ни заранее заданных ролей, ни заранее прописанного сценария работы. Ему передают начальную точку и цель, а он ищет путь через неизвестное пространство состояний. Первая область, где это проверено на практике, — автономное пентестирование. Но задумывается движок гораздо шире.
Проект написан на Python (FastAPI и uvicorn), распространяется под лицензией AGPL-3.0. Репозиторий: https://github.com/oritera/Cairn
Какую задачу решает Cairn
Пентест — это направленный поиск по почти бесконечному пространству состояний:
- Начало — известно: адрес цели или сама система.
- Цель — задана: получить shell, забрать флаг.
- Путь — неизвестен.
Такая же структура есть у множества других задач. Исследование уязвимостей, математическое доказательство, CTF — везде, где есть ясная стартовая точка, ясное условие успеха и неизвестный путь между ними, задача устроена одинаково. Cairn построен именно для таких задач, а пентестирование — первая область, где его проверили.
Три сущности: факт, намерение, подсказка
В основе движка лежит архитектура чёрной доски в современной переработке. Это когда несколько участников работают с общей доской: каждый читает текущее состояние, каждый добавляет на доску своё новое знание, а центрального планировщика нет. Классический пример такой архитектуры — система Hearsay-II из CMU, 1970 год.
В Cairn на доске живут всего три сущности:
| Сущность | Что это |
|---|---|
| Факт | Подтверждённая объективная находка, записанная на доску |
| Намерение | Объявленное направление разведки, которое ещё не выполнено |
| Подсказка | Решение человека, добавленное в любой момент; агенты подхватывают его при следующем чтении |
Граф растёт от origin к goal. Каждый новый факт — это очередной камень в cairn, а cairn по-английски как раз означает «пирамидка из камней», по которой альпинисты оставляют путь для следующих. Отсюда и название проекта.
Факты только добавляются и никогда не меняются. Изменение состояния выражается новым фактом. Например, в ходе разведки сети появляются три записи: f003 — «получен root shell на host-A», f007 — «через host-A найдена внутренняя сеть 10.0.2.0/24», f025 — «shell на host-A отвалился». Сам факт «shell отвалился» — объективная находка, поэтому он тоже попадает в граф. Агент, прочитавший граф, сам делает вывод о текущей достижимости и объявляет следующее намерение: восстановить shell или сменить опорную точку. Переписывать историю не нужно, и помечать старые факты как устаревшие тоже не нужно — сам порядок фактов уже несёт информацию об изменениях.
Намерение в графе — это ребро. При этом у одного намерения может быть несколько исходных фактов: несколько известных находок совместно поддерживают одну разведку, и все они сохраняются в связях, а не теряются.
Агенты без ролей
Воркеры Cairn работают по циклу OODA: Observe — наблюдают полный граф, Orient — сориентировались в текущем состоянии, Decide — решили, что делать дальше, Act — выполнили разведку. Находки записываются обратно на доску как новые факты.
У воркеров нет фиксированных ролей. Задачи рождаются на ходу из текущего состояния графа, а не из заранее написанных должностей вроде «разведчик» или «аналитик».
Всего есть три типа задач, и выполняет их один и тот же воркер:
| Задача | Что делает | Результат |
|---|---|---|
| Bootstrap | В начале проекта пробует решить задачу напрямую | Факт и, возможно, отметка о завершении |
| Reason | Читает весь граф: цель достигнута? что исследовать дальше? | Завершение, новые намерения или ничего |
| Explore | Берёт одно намерение, выполняет разведку, отчитывается | Один факт |
Агенты не общаются друг с другом напрямую. Единственный канал связи — общая доска. Один агент оставил на ней факт, другой увидел этот факт и на его основе принял решение. Такой способ координации в биологии называют стигмергией: муравьи выстраивают маршруты, оставляя на земле следы, и никто не говорит никому, куда идти.
Архитектура
Cairn Server хранит граф и следит только за его согласованностью. Никакой логики и никаких решений он не принимает.
Cairn Dispatcher читает граф, планирует задачи, поднимает и останавливает контейнеры воркеров. Это единственный компонент, который пишет в протокол.
Worker Container — свой на каждый проект, внутри него одновременно работает несколько воркеров. Воркер получает промпт и возвращает структурированный ответ.
Поддерживаются три бэкенда воркеров: Claude Code, Codex и Pi. Модель для каждого бэкенда задаётся в конфиге, поэтому один и тот же движок можно гонять на разных моделях.
Воркеры могут работать и напрямую на машине диспетчера, без контейнеров — об этом ниже.
Требования и запуск
Нужны macOS или Linux, Python не ниже 3.12 и Docker (в локальном режиме Docker не нужен).
Сначала скачивается образ контейнера с воркером:
docker pull --platform=linux/amd64 ghcr.io/oritera/cairn-worker-container:latest
Дальше создаётся конфиг диспетчера — его нужно заполнить адресами и ключами доступа к моделям. Пример лежит в репозитории: dispatch.example.yaml.
cp dispatch.example.yaml dispatch.yaml
Запуск через Docker Compose:
docker pull ghcr.io/astral-sh/uv:python3.13-trixie
docker compose up --build
Сервер поднимается на порту 8000, диспетчер стартует после того, как сервер пройдёт проверку состояния. Данные сохраняются в каталог ./datas/cairn/.
Запуск вручную, без Docker Compose:
# Запустить сервер
uv run --project cairn cairn serve
# Запустить диспетчер
uv run --project cairn cairn dispatch --config dispatch.yaml
В конфиге есть полезные ограничители. max_workers — общий предел числа одновременно работающих воркеров, max_running_projects — сколько проектов допустимо вести параллельно, max_project_workers — защита от того, чтобы один проект занял весь диспетчер, а tasks.reason.max_intents ограничивает, сколько новых намерений может породить один шаг Reason.
Локальный режим без Docker
Отдельный режим запускает воркеров как обычные процессы на машине диспетчера. Они используют уже настроенные и залогиненные CLI-инструменты claude, codex или pi — Docker не нужен, и ключи в конфиге тоже не нужны.
cp dispatch.local.example.yaml dispatch.yaml
uv run --project cairn cairn serve
uv run --project cairn cairn dispatch --config dispatch.yaml
Режим включается параметром runtime.execution: local в dispatch.local.example.yaml. Каждому проекту достаётся отдельный рабочий каталог внутри local.workspace_root.
Важное ограничение: в этом режиме агенты работают с правами вашего пользователя и без песочницы. Диспетчер надо запускать прямо на хосте, а не внутри контейнера, и только в тех окружениях, где у вас есть разрешение на работу.
Результаты
Cairn показал себя на хакатоне Tencent Cloud Hackathon, второе издание, в челлендже по AI-пентестингу. В соревновании участвовали 610 команд и 1345 человек из ведущих университетов и компаний по безопасности.
- Решено задач: 54 из 54 — единственная команда, взявшая максимум.
- Итоговое место: 3-е.
Систему до соревнования не тестировали. Полный конвейер подняли впервые в 4 часа ночи в день старта. Без предварительного обучения, без настройки, без профильных инструментов. Ноль MCP-инструментов, ноль RAG, ноль заранее прописанных ролей агентов.
Документация, лицензия и ответственность
Подробная спецификация протокола лежит в docs/specs/server-protocol.md, описание работы диспетчера — в docs/specs/dispatcher-design.md.
Лицензия — GNU AGPLv3, подробности в файле LICENSE. Для коммерческого или закрытого использования автор предлагает отдельную платную лицензию: нужно написать ему напрямую. Отправляя pull request, вы соглашаетесь с тем, что ваш вклад может использоваться и по AGPL-3.0, и по коммерческой лицензии проекта.
Авторы отдельно предупреждают: инструмент предназначен только для тех окружений, где у вас есть явное разрешение на работу. Использовать Cairn против чужих сетей, приложений и данных без разрения владельца незаконно. Ответственность за применение лежит на пользователе.
Источник: https://github.com/oritera/Cairn