- Дата публикации
Broccoli: open source‑агент, который превращает задачи в Linear в pull‑реквесты на вашем GCP
Что нового
Broccoli — это open source‑«тиммейт» для разработчиков, который живёт в вашем Google Cloud и сам превращает задачи в Linear в pull‑реквесты в GitHub.
Ключевые возможности:
- От задачи в Linear до PR без участия человека. Вы назначаете тикет на бота Broccoli — он планирует работу, пишет код, открывает pull‑реквест.
- Работа строго в вашем контуре. Всё разворачивается в вашем GCP‑проекте и Postgres. Нет внешнего control plane, данные не уходят за пределы вашего аккаунта.
- Продакшн‑стек с первого дня. Используются Cloud Run, Secret Manager, dedupe вебхуков, хранение состояния задач в базе.
- AI‑код‑ревью на каждый PR. Claude и Codex читают diff, оставляют комментарии и могут пушить фиксы по запросу.
- Гибкая система промптов. Шаблоны промптов лежат в репозитории: вы можете форкнуть, настроить и версионировать их вместе с кодом.
- Развёртывание примерно за 30 минут. Один bootstrap‑скрипт, один конфиг, две интеграции‑вебхука — и сервис в работе.
- Два режима развёртывания. Быстрый путь через «coding agent» (например, codex cli) или полностью ручной пошаговый сценарий.
Цен, квот и бенчмарков производительности авторы не приводят: скорость и стоимость зависят от тарифов Google Cloud, OpenAI и Anthropic.
Как это работает
Архитектура Broccoli строится вокруг двух Cloud Run‑компонентов и общей PostgreSQL‑базы.
Архитектура
Broccoli разворачивает в вашем GCP:
-
broccoli-oss-service — FastAPI‑сервис в Cloud Run.
- Принимает вебхуки GitHub и Linear.
- Проверяет подписи вебхуков.
- Дедуплицирует доставки (чтобы один и тот же вебхук не запустил задачу дважды).
- Создаёт записи задач в базе.
-
broccoli-oss-runner — Cloud Run Job.
- Забирает задачи из Postgres.
- Запускает автоматизацию через CLI‑клиенты codex и claude.
- Использует промпты, которые лежат в репозитории (vendored prompt templates).
-
Postgres — хранилище состояния:
- задания и их статус,
- доставки вебхуков,
- состояние PR,
- состояние задач в Linear,
- конфигурация репозиториев.
-
Secret Manager — хранилище чувствительных данных:
- приватный ключ GitHub App,
- секреты вебхуков GitHub и Linear,
- API‑ключи OpenAI и Anthropic,
- URL базы данных и пароль пользователя Postgres.
Подробная схема описана в ARCHITECTURE.md, контракт вебхуков и состояния — в JOB-CONTRACT.md.
Поток работы
- В Linear есть тикет. Вы назначаете его на отдельного бота‑пользователя, которого Broccoli использует как триггер.
- Linear посылает вебхук в Broccoli (
/webhooks/linear). - FastAPI‑сервис проверяет подпись, записывает задачу и создаёт job.
- Cloud Run Job‑runner поднимается, читает задачу, достаёт промпты и вызывает:
- Codex / OpenAI через CLI,
- Claude через CLI.
- Агент пишет код, открывает PR в GitHub от имени GitHub App.
- Claude и Codex читают diff, оставляют комментарии и при запросе пушат фиксы.
Все токены GitHub App генерируются на вашей стороне: сервис использует App ID и приватный PEM‑ключ для выпуска installation‑токенов.
Где живут промпты
Шаблоны промптов лежат в репозитории Broccoli и подтягиваются runner’ом. Вы можете:
- менять их под ваш стиль кода и процессы ревью;
- версионировать вместе с приложением;
- раскатывать изменения промптов через обычный CI/CD.
Что это значит для вас
Для чего Broccoli полезен
Broccoli рассчитан на команды, которые:
- уже живут в экосистеме Linear + GitHub + GCP;
- хотят автоматизировать рутину вокруг задач: создание PR, базовая реализация, мелкие фиксы;
- не готовы отдавать код и тикеты внешним SaaS‑агентам и предпочитают держать всё в своём облаке;
- готовы потратить время на аккуратную настройку GitHub App, Linear‑бота и секретов.
Типичные сценарии:
- Мелкие фичи и технический долг. Тикеты, где всё понятно: добавить флаг, поменять конфиг, обновить API‑вызов.
- Шаблонные изменения. Массовые правки по репозиторию, где промпт можно чётко описать.
- Первичный PR для большой задачи. Broccoli может собрать скелет решения, чтобы разработчик дальше довёл его до продакшна.
- AI‑код‑ревью. Claude и Codex дают второе мнение по каждому PR, находят простые баги, предлагают рефакторинг.
Где лучше не использовать
- Критичные изменения ядра продукта. Всё, что затрагивает безопасность, денежные потоки или сложные алгоритмы, всё равно потребует глубокого ручного ревью.
- Проекты без чёткой архитектуры и тестов. Агенту сложнее ориентироваться в хаотичном коде, а вам — проверять результат.
- Команды без GCP. Broccoli завязан на Google Cloud: Cloud Run, Secret Manager, Cloud SQL (по умолчанию). Если у вас AWS или «железо в стойке», придётся серьёзно адаптировать деплой.
Важные ограничения и нюансы
- Broccoli требует Google Cloud, GitHub и Linear. Без этих трёх систем он не заработает.
- Нужны активные платные API‑ключи OpenAI и Anthropic. Счёт за токены пойдёт по вашим аккаунтам.
- Продукт — open source и разворачивается самостоятельно. Нет «одной кнопки в браузере», придётся пройти все шаги настройки.
- Для России могут потребоваться VPN и платёжные решения, которые работают с Google Cloud, OpenAI и Anthropic.
Если у вас уже есть GCP‑инфраструктура и вы готовы инвестировать 30–60 минут в первый деплой, Broccoli может снять часть рутины с команды и дать управляемый вход в «AI‑тиммейтов» без стороннего SaaS.
Место на рынке
По сути Broccoli — это self‑hosted‑агент для разработки, который конкурирует не с одной моделью, а с целым классом решений:
- SaaS‑агенты для GitHub/Linear. Они обычно проще в запуске, но требуют доверять внешнему сервису код и тикеты.
- GitHub Copilot и аналоги. Copilot живёт в IDE и помогает писать код построчно, но не управляет задачами и не открывает PR по тикетам.
- Внутренние скрипты и боты. Многие команды уже пишут свои интеграции между Linear, GitHub и CI, но редко доводят их до уровня полноценного агента с LLM.
Отличия Broccoli:
- Развёртывание только в вашем GCP. Нет отдельного control plane, вся логика живёт в вашем проекте, вы управляете секретами и базой.
- Жёсткая интеграция с Linear. Триггер — назначение задачи на специального бот‑пользователя. Это понятная модель для команд, которые уже живут в Linear.
- Использование Claude и Codex как движков. Broccoli не навязывает одну «универсальную» модель и опирается на два проверенных LLM‑провайдера.
Прямых численных сравнений с GPT‑4o, Claude 3.5 и другими агентами авторы не приводят. Основной акцент — на контроле инфраструктуры и на связке Linear+GitHub+GCP.
Установка
Broccoli можно развернуть двумя путями:
- Поручить большую часть работы внешнему coding‑агенту (например, codex cli), передав ему специальный промпт.
- Пройти все шаги вручную.
Ниже — оба сценария с сохранением всех команд и конфигураций.
Как запустить через coding‑агента
Авторы предлагают скопировать этот промпт в любимого coding‑агента (у них — codex cli):
Deploy this repository to my Google Cloud project. If I only gave you the GitHub repo URL, clone the repo first. If I already opened the repo locally, work from the existing checkout. Use the repo's deployment instructions, scripts, and `.agents/skills/broccoli-oss-gcp-deploy/SKILL.md`. Treat this as a request to deploy the app, not just inspect the codebase. Do not assume I have any of the prerequisites done yet. Before discovery, walk me through these checkpoints one at a time, and for each one confirm my answer before moving on. If a section of the README covers the step, point me to it instead of re-explaining.
1. GCP project + billing. Ask whether I already have a Google Cloud project with billing attached, and whether `gcloud` is logged in to that account. If not, walk me through creating the project at https://console.cloud.google.com/cloud-resource-manager and attaching billing at https://console.cloud.google.com/billing/projects, or offer to have the deployment skill create the project for me. Record the Project ID.
2. GitHub App. Ask whether I have already created a GitHub App for Broccoli with the required permissions (Contents, Pull requests, Issues = read/write; Metadata = read-only; subscribed to the `Pull request review` event). If not, walk me through `README.md -> Deploy it on your GCP -> 1. Create a GitHub App` step by step. Have me record the numeric App ID and download the private key PEM file locally. Placeholder Homepage/Webhook URLs are fine for now; bootstrap will print the real URLs.
3. Linear bot user + API key. IMPORTANT: the Linear API key must belong to a dedicated Linear bot user, NOT my personal account. A personal key silently breaks the "issue assigned to bot triggers a run" flow. Ask whether a dedicated bot user already exists. If not, walk me through `README.md -> 2. Designate a Linear bot user`: create or designate a Linear user, add it to every team whose issues should route through Broccoli, then log in as that bot user (or have an admin switch to that user) and generate the API key from that user's settings page. Before you accept the key as ready, explicitly confirm with me that it came from the bot user and not from my personal account. Record the bot user id.
4. OpenAI + Anthropic API keys. Ask whether I already have active API keys with billing enabled on each account. If not, send me to the OpenAI and Anthropic API keys pages to create them.
5. Linear webhook. This one comes later and is configured after bootstrap prints the service URL. Just tell me now that once the service URL exists, I will add a Linear webhook pointing at `${Service URL}/webhooks/linear` using the auto-generated `broccoli-oss-linear-webhook-secret` and subscribe to Issue and Issue label events. I do not need to do anything for this step yet.
6. Secret Manager population. Once the target project exists, for each of the four operator-managed secrets (`broccoli-oss-github-app-private-key-pem`, `broccoli-oss-linear-api-key`, `broccoli-oss-openai-api-key`, `broccoli-oss-anthropic-api-key`) give me the exact Secret Manager console URL for the target project and pause until I confirm each secret has a `latest` version. You retrieve the auto-generated webhook and DB password secrets yourself after bootstrap; I do not touch those.
Workflow after the checkpoints above:
- Run a non-mutating discovery step and fail fast on missing `gcloud` auth, billing access, org or project permissions, or other required local tools.
- If I do not already have a target GCP project, create or prepare one first.
- Before making cloud changes, show me the resolved deployment plan and any missing non-secret inputs.
- Never ask me to paste secrets into chat. If required secrets are missing, tell me exactly which secret names I need to populate in the target project and pause until I confirm they are present.
- Prefer the repo's existing deploy scripts, documented defaults, and post-deploy checks over guesswork.
- Use the Cloud Build path by default instead of local Docker.
- After deployment, continue through the verification steps you can safely run, then report the service URL, any remaining manual setup (including the Linear webhook from checkpoint 5), and the smoke-test result.
This is the fast path if you want the agent to drive the deployment for you. If you want the manual step-by-step path instead, use the guide below; it starts from project creation and shows exactly where the manual setup happens.
Этот промпт заставляет coding‑агента строго следовать README, не просить у вас секреты и использовать Cloud Build по умолчанию.
Ручное развёртывание в GCP
Ниже — сокращённый, но полный по шагам сценарий ручной установки. Все команды сохранены без изменений.
0. Создайте или выберите GCP‑проект
Нужен проект Google Cloud с включённым биллингом.
Если проект уже есть:
- Откройте его в GCP Console.
- Запишите Project ID.
- Убедитесь, что к проекту привязан биллинг.
Если проекта нет:
- Откройте страницу управления ресурсами:
https://console.cloud.google.com/cloud-resource-manager - Создайте проект.
- Привяжите биллинг:
https://console.cloud.google.com/billing/projects - Запишите новый Project ID.
Если вы используете навык broccoli-oss-gcp-deploy, он может:
- создать проект;
- привязать биллинг;
- включить нужные API;
- создать контейнеры секретов в Secret Manager.
1. Создайте GitHub App
Broccoli использует GitHub App, а не Personal Access Token.
Права репозитория:
- Contents: read/write
- Pull requests: read/write
- Issues: read/write
- Metadata: read-only
Подписка на события:
Pull request review
На этом этапе:
- задайте временные Homepage URL и Webhook URL (placeholder);
- запишите App ID (числовой идентификатор);
- скачайте приватный ключ PEM.
PEM‑файл нужен Broccoli для аутентификации в GitHub как приложение. Держите его локально, в чат не вставляйте.
2. Назначьте бота в Linear
Broccoli реагирует на задачи, назначенные на отдельного пользователя в Linear.
Сделайте так:
- создайте или выберите отдельного пользователя Linear как бота;
- добавьте его во все команды, чьи задачи должны идти через Broccoli;
- войдите под этим пользователем (или переключитесь как администратор);
- сгенерируйте API‑ключ Linear для этого пользователя;
- запишите bot user id — он понадобится при инициализации базы.
Важно: API‑ключ должен принадлежать боту, а не вашему личному аккаунту, иначе триггер по назначению задачи не сработает.
3. Откройте Secret Manager в нужном проекте
Секреты Broccoli хранятся в Google Cloud Secret Manager в том же проекте, где вы разворачиваете сервис.
- Откройте Secret Manager:
https://console.cloud.google.com/security/secret-manager - В селекторе проекта выберите ваш Broccoli‑проект.
- Убедитесь, что Project ID совпадает с записанным на шаге 0.
Если broccoli-oss-gcp-deploy уже создал некоторые секреты, вы можете зайти в них и нажать Add new version, а не создавать заново.
4. Заполните обязательные секреты
Эти значения нельзя отдавать агенту или скрипту, их нужно ввести вручную.
Для каждого секрета:
- нажмите Create secret или откройте существующий;
- используйте точное имя секрета;
- вставьте значение или загрузите файл;
- сохраните и убедитесь, что появился
latest‑version.
Обязательные секреты до запуска bootstrap:
| Secret | Откуда берётся | Что сделать |
| ------ | -------------- | ---------- |
| broccoli-oss-github-app-private-key-pem | PEM‑файл GitHub App (шаг 1) | Вставьте содержимое PEM как значение секрета |
| broccoli-oss-linear-api-key | API‑ключ бота Linear (шаг 2) | Вставьте ключ |
| broccoli-oss-openai-api-key | Страница API‑ключей OpenAI | Вставьте ключ |
| broccoli-oss-anthropic-api-key | Страница API‑ключей Anthropic | Вставьте ключ |
Дополнительные секреты (если идёте по «сырому» shell‑пути из README):
| Secret | Назначение | Как получить |
| ------ | ---------- | ------------ |
| broccoli-oss-db-password | Пароль пользователя broccoli_oss в Postgres; используется для broccoli-oss-database-url при Cloud SQL | Сгенерируйте случайное значение, например openssl rand -hex 32 |
| broccoli-oss-gh-webhook-secret | Общий секрет для подписи вебхуков GitHub | Сгенерируйте openssl rand -hex 32, то же значение вставьте в настройках GitHub App |
| broccoli-oss-linear-webhook-secret | Общий секрет для подписи вебхуков Linear | Сгенерируйте openssl rand -hex 32, то же значение вставьте в настройках вебхука Linear |
Для стандартного пути с Cloud SQL:
- не заполняйте
broccoli-oss-database-urlзаранее —deploy/bootstrap.shсам создаст секрет на основе Cloud SQL connection name иbroccoli-oss-db-password; - обязательно создайте
broccoli-oss-db-password.
Для локальной разработки или кастомных деплоев runner также принимает CODEX_API_KEY вместо OPENAI_API_KEY.
5. Сборка и пуш образов через Cloud Build
Перейдите в корень репозитория и выполните:
cd path/to/this-repo
export GCP_PROJECT_ID=your-project
export GCP_REGION=us-central1
export TAG=v0.1.0
export PUSH=1
./deploy/build-and-push.sh
По умолчанию deploy/build-and-push.sh использует Google Cloud Build. Образы собираются и пушатся внутри вашего GCP‑проекта, локальный Docker не нужен.
Скрипт выведет:
SERVICE_IMAGE=...RUNNER_IMAGE=...
Эти значения понадобятся на следующем шаге.
Если хотите собирать локально через Docker:
export BUILD_BACKEND=docker
./deploy/build-and-push.sh
6. Запустите bootstrap
deploy/bootstrap.sh — идемпотентный скрипт. Его можно безопасно запускать повторно: он обновляет переменные окружения и секреты Cloud Run инкрементально.
Пример запуска:
export GCP_PROJECT_ID=your-project
export GCP_REGION=us-central1
export GITHUB_APP_ID=123456
export SERVICE_IMAGE=us-docker.pkg.dev/your-project/containers/broccoli-oss-service:v0.1.0
export RUNNER_IMAGE=us-docker.pkg.dev/your-project/containers/broccoli-oss-runner:v0.1.0
# Common optional overrides:
export INGRESS_SERVICE_NAME=broccoli-oss-service
export RUNNER_JOB_BASENAME=broccoli-oss-runner
export RUNNER_TIMEOUT_SECONDS=3600
export DB_BACKEND=cloudsql
export DB_INSTANCE_NAME=broccoli-oss-pg
export DB_AUTHORIZED_NETWORKS=0.0.0.0/0
./deploy/bootstrap.sh
Bootstrap напечатает:
- URL развёрнутого сервиса;
- URL вебхука GitHub (
${Service URL}/webhooks/github); - URL вебхука Linear (
${Service URL}/webhooks/linear); - имена ресурсов Cloud Run (service и job).
Если DB_BACKEND=cloudsql, скрипт также:
- добавит публичный IPv4 к инстансу Cloud SQL;
- установит
authorizedNetworksизDB_AUTHORIZED_NETWORKS(по умолчанию0.0.0.0/0).
После этого:
- вернитесь в настройки GitHub App;
- задайте Homepage URL и Webhook URL из вывода bootstrap;
- вставьте значение
broccoli-oss-gh-webhook-secretв поле webhook secret GitHub App.
7. Установите GitHub App на репозиторий
В настройках GitHub App:
- нажмите Install App;
- выберите аккаунт или организацию, где лежит репозиторий;
- выберите Only select repositories, если не нужен широкий доступ;
- дайте доступ к нужному репозиторию.
Из URL установки возьмите installation id:
/settings/installations/<id> — он понадобится при сидировании базы.
8. Миграции и сидирование конфигурации репо
Для стандартного деплоя Cloud Run + Cloud SQL секрет broccoli-oss-database-url создаётся для рантайма Cloud Run и использует Unix‑сокет /cloudsql/.... Для локальных операторских команд такой URL не подходит.
Сделайте локальный TCP‑туннель через Cloud SQL Auth Proxy и соберите локальный DATABASE_URL на основе broccoli-oss-db-password:
cloud-sql-proxy your-project:us-central1:broccoli-oss-pg --port 5432
DB_PASSWORD="$( gcloud secrets versions access latest \
--secret=broccoli-oss-db-password \
--project your-project )"
export DATABASE_URL="postgresql://broccoli_oss:${DB_PASSWORD}@127.0.0.1:5432/broccoli_oss"
uv sync --dev
uv run python -m app.operator migrate
uv run python -m app.operator schema-version
Если вы используете навык Codex после bootstrap, он может сам:
- достать секреты из Secret Manager;
- запустить
migrate,schema-version,seed,preflightвнутри временного Cloud Run Job; - удалить временный job после завершения.
Команда для этого пути:
python .agents/skills/broccoli-oss-gcp-deploy/scripts/deploy.py \
--github-app-id <github-app-id> \
--project-id your-project \
--apply \
--post-deploy-operator \
--github-repo-full-name acme/demo \
[--git-clone-url https://github.com/acme/demo.git] \
[--default-branch main] \
[--github-installation-id 12345678] \
[--linear-team-id <linear-team-id>] \
[--linear-bot-user-id <linear-bot-user-id>]
Любые опциональные флаги можно опустить, если навык может безопасно получить значения из секретов и API целевого проекта.
Как найти Linear bot user id и team id
Используйте уже созданный секрет с API‑ключом Linear:
LINEAR_API_KEY="$( gcloud secrets versions access latest \
--secret=broccoli-oss-linear-api-key \
--project your-project )"
curl -s https://api.linear.app/graphql \
-H "Authorization: ${LINEAR_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"query":"query ViewerAndTeams { viewer { id name } teams { nodes { id key name } } }"}'
В ответе будут:
viewer.id— обычно это id бота, если ключ принадлежит боту;teams.nodes[].id— кандидаты дляlinear_team_id.
Подготовка seed‑файла
Отредактируйте db/seed/example.seed.yaml (или его копию):
repos:
- repo_key: demo
enabled: true
github_repo_full_name: acme/demo
github_installation_id: 12345678 # from Step 7 install URL /settings/installations/<id>
git_clone_url: https://github.com/acme/demo.git
default_branch: main
base_branch: main
linear_team_id: <linear-team-uuid>
config_json: {}
global:
linear_bot_user_id:
userId: <linear-bot-user-id> # from Step 2
Поддерживаются верхнеуровневые ключи:
repos;global(сlinear_bot_user_id).
Сидер отклонит:
- дублирующиеся
repo_key; - дублирующиеся
github_repo_full_name; - пустые обязательные строки;
- неизвестные ключи.
Запустите сидирование:
uv run python -m app.operator seed --file db/seed/example.seed.yaml
9. Зарегистрируйте вебхуки
Сначала достаньте сгенерированные секреты вебхуков:
gcloud secrets versions access latest \
--secret=broccoli-oss-gh-webhook-secret \
--project your-project
gcloud secrets versions access latest \
--secret=broccoli-oss-linear-webhook-secret \
--project your-project
Дальше:
- GitHub App‑вебхук вы уже настроили на шаге 6 (URL и секрет).
- В Linear, когда у вас будет URL сервиса, создайте вебхук на:
${Service URL}/webhooks/linear
Используйте секретbroccoli-oss-linear-webhook-secretи подпишитесь на события Issue и Issue label.
После этого можно назначать задачи в Linear на бота и наблюдать, как Broccoli создаёт PR в GitHub.