Skip to content

Latest commit

 

History

History
292 lines (212 loc) · 34.7 KB

File metadata and controls

292 lines (212 loc) · 34.7 KB
Bernstein
Bernstein - the open-source governance layer for AI agents

"To achieve great things, two things are needed: a plan and not quite enough time." - attributed to Leonard Bernstein

опенсорсный governance-слой для AI-агентов

CI PyPI GHCR Python 3.12+ License OpenSSF Scorecard CodeQL Open in Codespaces MCP Toplist Ask DeepWiki

website · docs · install · first run · glossary · limitations · name policy · sponsor

简体中文 · 繁體中文 · 日本語 · 한국어 · हिन्दी · বাংলা · Русский · Español · Português · Deutsch · Français · Italiano · Nederlands · Polski · Svenska · Suomi · Українська · Türkçe · العربية · עברית · Bahasa Indonesia · Tiếng Việt · ไทย


Статус: beta. Сопровождается одним человеком, активно разрабатывается. Номер версии считает релизы, а не зрелость — минорные версии могут менять интерфейсы. Фиксируй версию для всего, от чего зависишь; регрессии чиним быстро, заводи их.

Bernstein — опенсорсный governance-слой для AI-агентов. Работает на policy as code: ты описываешь политику — кто что может делать, что требует подтверждения, что должно фиксироваться — а Bernstein применяет её и формирует проверяемую запись. Детерминированный планировщик — в цикле координации нет модели — гоняет агентов параллельно, проверяет результат на гейтах и записывает каждый шаг, так что прогон можно верифицировать постфактум, офлайн, по одним лишь артефактам. CLI-агенты для кода работают из коробки (Claude Code, Codex, Gemini CLI и ещё 40+), и тот же слой говернит любую агентную нагрузку: результатом может быть дифф, исследовательский отчёт, датасет или пакет аудиторских свидетельств. Профиль установки для air-gap в комплекте. Apache-2.0.

коротко

Отличают его четыре вещи; всё остальное — детали.

  • В цикле координации нет LLM. Планирование — обычный Python, поэтому прогон воспроизводим от начала до конца. Переиграй вчерашний план — получишь вчерашний граф задач.
  • Проверяемо постфактум. Журнал replay пишется на каждом прогоне, постоянно включённый lineage-хребет фиксирует каждый шаг, несущий происхождение; опциональный HMAC-сцепленный аудит-лог (BERNSTEIN_AUDIT=1) добавляет квитанции, проверяемые офлайн. Недетерминизм всплывает как расхождение хеша на конкретном шаге, а не как флейкующий перезапуск. С некодовыми результатами так же: задача может объявить контракт артефакта (отчёт, датасет, лог действий, результат ops-операции) и завершается подписанной lineage-квитанцией, а не git-коммитом.
  • Изоляция по построению. Каждая кодовая задача получает свой git worktree за merge-гейтами; задачи в artifact-режиме — рабочий каталог под .sdd/workspaces/. По умолчанию агенты не делят изменяемое рабочее пространство; единственное общее состояние — бэклог задач, и он захватывается атомарно. Более жёсткие ограничения файловой системы включаются отдельно, через sandbox-бэкенды. Выключи worktree — и все задачи пойдут в общем checkout.
  • Широко и локально. 40+ адаптеров CLI-агентов плюс универсальная обёртка --prompt, состояние в файлах, без похода в SaaS, без чужого data plane.

Полный список — на странице возможностей; матрица возможностей — исчерпывающий индекс.

как выглядит прогон

Один YAML-файл объявляет весь прогон: фазы, роли, зависимости и условия, при которых узел вообще запускается. Планировщик исполняет его как обычный Python — в файле нет ни одного промпта, и ни одна модель не решает, что будет дальше. Этот граф собирает пакет аудиторских свидетельств; полный файл лежит в .bernstein/workflows/audit-evidence-pack.yaml.

name: audit-evidence-pack
version: "1.0.0"

phases:
  - name: scope
    allowed_roles: [manager, architect]
  - name: collect
  - name: validate
    allowed_roles: [qa, security]
  - name: deliver
    allowed_roles: [security, manager]

nodes:
  define-control-inventory:
    phase: scope
    role: architect

  collect-audit-logs:
    phase: collect
    role: security
    depends_on: [define-control-inventory]

  # three more evidence streams collect in parallel:
  # collect-sboms-and-attestations, collect-runbooks-and-policies,
  # collect-eval-results

  assemble-pack:
    phase: validate
    role: docs
    depends_on:
      - collect-audit-logs
      - collect-sboms-and-attestations
      - collect-runbooks-and-policies
      - collect-eval-results

  mock-auditor-pass:
    phase: validate
    role: qa
    depends_on: [assemble-pack]

  remediate-findings:
    phase: collect
    role: docs
    depends_on:
      - source: mock-auditor-pass
        condition: "status == 'failed'"
    retry:
      max_attempts: 3
      until: "status == 'done'"

  sign-and-deliver:
    phase: deliver
    role: security
    depends_on:
      - source: mock-auditor-pass
        condition: "status == 'done'"
flowchart LR
    inv[define-control-inventory] --> logs[collect-audit-logs]
    inv --> sbom[collect-sboms-and-attestations]
    inv --> rb[collect-runbooks-and-policies]
    inv --> ev[collect-eval-results]
    logs --> pack[assemble-pack]
    sbom --> pack
    rb --> pack
    ev --> pack
    pack --> gate{mock-auditor-pass}
    gate -->|failed| fix["remediate-findings (retry x3)"]
    gate -->|done| sign[sign-and-deliver]
Loading

Каждый узел забирает агент, чья роль разрешена фазой; ролевые ограничения и гейты одобрения держатся независимо от того, что агент делает внутри задачи. Кодовый узел завершается за merge-гейтами в собственном git worktree. Узлы выше завершаются иначе: контракт артефакта называет результат (отчёт, датасет, скан, лог действий), и узел закрывается подписанной lineage-квитанцией вместо коммита. Тот же планировщик, тот же журнал, та же офлайн-верификация — несёт ли граф код, исследование, ops-изменение или всё сразу. Готовые графы для софта, исследований, документации, энтерпрайза и контрибьюторских процессов лежат в .bernstein/scenarios/.

установка за 30 секунд

uv tool install bernstein    # or: pipx install bernstein
bernstein init
bernstein doctor             # checks a CLI agent is installed and authenticated
bernstein -g "fix the failing test in tests/test_foo.py"

pipx, pip, brew, dnf, npm и Docker описаны в руководстве по установке; у air-gap-wheelhouse своё руководство.

Настоящий демонстрационный прогон bernstein: mock-агенты чинят четыре засеянных бага, финал — подписанная квитанция прогона, проверяемая офлайн

Запись выше — настоящий прогон, и он поставляется вместе с доказательством. Каст, подписанная квитанция прогона, выведенная из журнала этого прогона, и публичный ключ, который её привязывает, лежат в docs/assets/demo-run/. Проверить прогон, который ты только что посмотрел, офлайн:

bernstein verify receipt docs/assets/demo-run/run-receipt.json \
    --public-key docs/assets/demo-run/run-receipt.pub.pem

CI перепроверяет закоммиченную квитанцию на каждом пуше в main — и доказывает, что подделанная копия не проходит, — так что опубликованное свидетельство не сгниёт в декоративный файл. scripts/record_demo.sh пересобирает запись, квитанцию и ключ из свежего настоящего прогона; ничего в терминале не синтезировано.

За идущим прогоном можно смотреть с любой из двух операторских поверхностей. Обе читают один и тот же task API, так что ни одна не является отстающим зеркалом другой. В bernstein live левая и правая колонки прокручиваются независимо, целыми панелями, так что виджеты, не поместившиеся на экран, остаются доступны в невысоких терминалах.

Терминальный дашборд в две колонки: слева агенты с живыми логами, справа доска задач, снизу лента активности во всю ширину и строка стоимости Браузерный дашборд со списком из шестидесяти двух задач, одиннадцать выполняются, одна раскрыта до диффа рабочего дерева
bernstein live — терминальный дашборд bernstein gui serve — браузерный дашборд

проверить прогон

Детерминизм здесь — то, что проверяют, а не то, что принимают на веру. Прогони один раз с включённым аудитом, потом проверь записанное:

BERNSTEIN_AUDIT=1 bernstein -g "fix the failing test in tests/test_foo.py"
bernstein replay list                 # run ids recorded on disk
bernstein replay latest --verify      # recompute the journal head, name the first divergent step
bernstein lineage verify <run_id>     # recompute the always-on lineage spine
bernstein audit verify                # HMAC chain + Merkle seal (written because audit was enabled)
bernstein audit diagnose <run_id> --signal gate --sign-key KEY
                                      # name the exact step a failure entered the run, as a signed receipt
bernstein verify run <run_id> --signing-key-path key.pem   # sign one portable run receipt
bernstein verify receipt .sdd/runs/<run_id>/run-receipt.json  # verify it offline: file only

Журнал пишется на каждом прогоне; lineage-хребет включён всегда и получает запись на каждый шаг, несущий происхождение, так что короткий прогон может закончиться валидным пустым хребтом. Проверять цепочку в bernstein audit verify есть что только если прогон был запущен с BERNSTEIN_AUDIT=1, с compliance-пресетом или через bernstein run --audit. Флаг --audit принадлежит bernstein run; для формы bernstein -g выше задавай переменную окружения.

Одна квитанция прогона связывает голову журнала, голову lineage-хребта (если прогон писал записи хребта) и, опционально, диапазон аудит-цепочки — под одним субъектом, подписанным Ed25519, с вложенным публичным ключом. Ревьюер, у которого есть этот файл и публичный ключ оператора, может подтвердить, что вложенные действия и цепочки не менялись: без HMAC-ключа, без живого .sdd/, а при подделке — выход 2 с указанием первого разошедшегося шага. Квитанция идентифицирует то состояние журнала, которое в неё вложено; чтобы доказать, что это состояние и есть полный завершённый журнал, нужна отдельная независимая печать головы и счётчика. Если есть только файл и не задана привязка --public-key, проверка даёт лишь целостность: она доказывает, что квитанция внутренне согласована, но не то, кто её подписал, — и вердикт это прямо говорит. Подробности — в детерминированном replay.

Та же проверяемость распространяется на цифры оценки. bernstein bench run <suite> --reliability k (то же самое пишется как bernstein eval --reliability k) прогоняет каждую задачу k раз при фиксированной координации и выдаёт нижнюю границу pass^k (должны пройти все k попыток) рядом с потолком pass@1. Результат запечатан в подписанной квитанции, которую bernstein bench reliability-verify пересчитывает офлайн, так что выдуманная нижняя граница проверку не проходит. Подробности: нижняя граница надёжности pass^k.

как это работает

Каждая цель проходит четыре стадии:

  1. Decompose. Manager разбивает цель на задачи с ролями, закреплёнными файлами и сигналами завершения. Один вызов LLM, дальше — обычный Python.
  2. Spawn. Агенты стартуют в изолированных git worktree, по одному на кодовую задачу; задача в artifact-режиме получает вместо этого обычный рабочий каталог. Ветка main остаётся чистой.
  3. Verify. Janitor проверяет конкретные сигналы: тесты проходят, файлы на месте, линтер чист, типы сходятся.
  4. Merge. Проверенная работа попадает в main. Упавшие задачи ретраятся или уходят на другую модель.

Почему планировщик — обычный Python и чем за это платим: почему детерминизм.

повседневные команды

cd your-project
bernstein init                    # creates .sdd/ workspace, bernstein.yaml + templates/
bernstein -g "Add rate limiting"  # agents spawn, work in parallel, verify, exit
bernstein live                    # watch progress in the TUI dashboard
bernstein run plan.yaml           # multi-stage plan: skip LLM planning, execute directly
bernstein stop                    # graceful shutdown with drain

Полная операторская поверхность (автоматизация PR, расписания, чат-мосты, autofix-демон) — в командах оператора.

bernstein workflow выполняет декларативные YAML-DAG из узлов agent / command / loop — с поддержкой возобновления прерванных прогонов:

bernstein workflow run idea-to-pr -g "Add JWT auth"   # prints run_id
bernstein workflow resume <run_id>                    # picks up at the first non-completed node

Контрольные точки прогона попадают в .sdd/runs/<run_id>/ на каждом узле. Возобновление проверяет хеш манифеста в начале прогона, поэтому изменившаяся спецификация приводит к отказу, а не к молчаливому выполнению другого манифеста. См. манифесты workflow.

Гейты гигиены репозитория: bernstein readme-l10n verify роняет PR, в котором переводы README разошлись с английским источником (называя устаревшую секцию), bernstein readme-l10n sync перепривязывает их после правки английского. См. readme-l10n.

поддерживаемые агенты

Claude Code, Codex CLI, Gemini CLI, GitHub Copilot CLI, Cursor, Aider, Goose, Muse Code, OpenAI Agents SDK, Amp, Cody, Continue, Devin Terminal, Junie, Kilo, Kiro, AWS Q Developer, Ollama, OpenCode, OpenHands, Open Interpreter, gptme, Plandex, AIChat, Letta Code, Qwen и другие. В индексе адаптеров есть команды установки для 30 из них. bernstein integrations list перечисляет все 54 встроенную интеграцию из src/bernstein/adapters/registry.py — единственного источника правды о том, что резолвится. 52 из них — выбираемые адаптеры агентов; остальные две строки это тестовая заглушка mock и профиль эндпоинтов self-hosted-endpoints. Всё прочее, у чего есть флаг --prompt, работает через универсальную обёртку.

Смешивай агентов в одном прогоне: дешёвые локальные модели на бойлерплейт, тяжёлые облачные — на архитектуру. bernstein integrations list --installed покажет, что доступно на твоей машине.

добровольные вычисления

Проект может пометить задачи как открытые для добровольцев, и любой может выполнить одну из них на своей машине без учётной записи и без координатора. Что задаче разрешено делать, проект объявляет в манифесте volunteer.json — бэкенд песочницы, список разрешённых сетевых адресов, потолки по времени и памяти, — а собственные лимиты донора могут только сузить это, но не расширить. Квитанция завершённой задачи привязывает результат к тому решению об изоляции, под которым он получен, поэтому сопровождающий и через месяцы может проверить, к чему работа действительно имела доступ.

bernstein volunteer verify .
bernstein volunteer browse --budget 60

Руководство донора описывает запуск воркера и бюджет, который вы задаёте, руководство проекта — объявление манифеста, а модель угроз — что каждая граница защищает, а что нет. Запуск одной командой ещё не выпущен: сегодня работают подкоманды verify, browse и hub.

за пределами первой страницы

Всё глубокое живёт на сайте документации:

страница о чём
возможности полный список возможностей: режим MCP-сервера, подписанные карточки агентов, sandbox-бэкенды, приёмники артефактов, отображение на регуляторные требования
кому это нужно где польза реальна и где Bernstein — неподходящий инструмент
workflow декларативные YAML-DAG из узлов agent / command / loop
веб-интерфейс браузерный дашборд на том же API, что и TUI
облачное исполнение экспериментально: запуск агентов на Cloudflare Workers с синхронизацией workspace в R2 под твоим аккаунтом. Хостинг-сервис api.bernstein.run пока недоступен
источники данных квитанции на read-only запросы плюс драйвер запросов, привязывающий каждый результат к снимку схемы, против которого он получен
каталоги агентов направь роли на определения агентов вне встроенных шаблонов — обычный каталог YAML/SKILL.md или дерево в раскладке плагина Claude Code
безопасность scorecard, фаззинг, харденинг
архитектура как оно устроено внутри

почему такое название?

Bernstein назван в честь Леонарда Бернстайна, американского дирижёра и композитора. Проект дирижирует бригадой CLI-агентов так же, как Бернстайн дирижировал Нью-Йоркским филармоническим: каждый вступает вовремя, партитура детерминирована, за результат отвечает дирижёр.

я написал bernstein, потому что платил $400 в месяц по счетам claude, гоняя трёх кодовых агентов параллельно, и получал недетерминированные мержи. Apache 2.0, сопровождается одним человеком. Живая статистика: bernstein.run.

где упоминают

Есть в vinta/awesome-python, попал в обзор Augment Code open-source agent orchestrators и в Python Weekly #742. Сам подход мы описали как паттерн deterministic zero-LLM orchestration в awesome-agentic-patterns.

Все упоминания: 20+ awesome-списков, каталогов, рассылок и цитирований

Полный отслеживаемый список — каждая запись в awesome-листах, каждое попадание в каталог, каждое цитирование как prior art и каждое упоминание в рассылке — лежит в docs/mentions.md. Записи добавляются по мере появления; поправки приветствуются через issue или PR.

участие, поддержка, лицензия

PR приветствуются; сетап и стиль кода — в CONTRIBUTING.md. Сообщения о проблемах безопасности идут через SECURITY.md. Если Bernstein экономит тебе время: GitHub Sponsors. Связь: forte@bernstein.run.

Метаданные для цитирования — в CITATION.cff. Лицензия: Apache-2.0; имя проекта покрыто отдельно в TRADEMARKS.md.


Alex Chernysh · GitHub · X · bernstein.run