GitLab CI/CD и headless-автоматизация

Если в предыдущей статье у нас был готовый claude-code-action — обёртка, которую достаточно добавить в YAML и всё заработает — то с GitLab история другая. Здесь нет готового «action», и это на самом деле плюс: вы работаете напрямую с CLI через headless-режим, что даёт полный контроль над каждым вызовом.

> Статус: Официальная интеграция Claude Code с GitLab CI/CD находится в бета-версии и поддерживается командой GitLab. Актуальный трекер — gitlab.com/gitlab-org/gitlab/-/issues/573776.

Headless-режим: что происходит внутри

Флаг -p (или --print) превращает Claude из интерактивного собеседника в инструмент командной строки: запустил → агентный цикл выполнился → вышел с кодом 0 или ненулевым. Это и есть headless-режим.

# Простейший вызов: прочитать и проанализировать
claude -p "Найди потенциальные баги в src/auth/" --allowedTools "Read,Bash"

# С JSON-выводом — удобно парсить в CI
claude -p "Проверь code style" --output-format json | jq -r '.result'

# Передать данные через pipe
git diff origin/main | claude -p "Сделай ревью этого диффа" --output-format text

В конвейере важны три флага:

  • --max-turns N — ограничить количество шагов агентного цикла, иначе агент может крутиться неограниченно
  • --max-budget-usd N — жёсткий потолок затрат на один вызов (только в print-режиме)
  • --permission-mode acceptEdits — разрешить запись файлов без подтверждения, что нужно для автоматических правок
sequenceDiagram participant U as Пользователь / Триггер participant GL as GitLab CI/CD participant R as Runner (контейнер) participant C as claude -p participant AG as Агентный цикл participant Repo as Репозиторий U->>GL: Событие (MR / schedule / web / @claude) GL->>R: Запуск job: node:24-alpine3.21 R->>R: apk add git curl bash R->>R: curl install.sh | bash R->>C: claude -p "$AI_FLOW_INPUT" --allowedTools ... loop Агентный цикл C->>AG: Планирование шага AG->>Repo: Read / Edit / Bash Repo-->>AG: Результат инструмента AG->>C: Наблюдение → следующий шаг end C-->>R: Итог (text / json) R->>Repo: git commit + push Repo->>GL: Новый MR или комментарий
sequenceDiagram
    participant U as Пользователь / Триггер
    participant GL as GitLab CI/CD
    participant R as Runner (контейнер)
    participant C as claude -p
    participant AG as Агентный цикл
    participant Repo as Репозиторий

    U->>GL: Событие (MR / schedule / web / @claude)
    GL->>R: Запуск job: node:24-alpine3.21
    R->>R: apk add git curl bash
    R->>R: curl install.sh | bash
    R->>C: claude -p "$AI_FLOW_INPUT" --allowedTools ...
    loop Агентный цикл
        C->>AG: Планирование шага
        AG->>Repo: Read / Edit / Bash
        Repo-->>AG: Результат инструмента
        AG->>C: Наблюдение → следующий шаг
    end
    C-->>R: Итог (text / json)
    R->>Repo: git commit + push
    Repo->>GL: Новый MR или комментарий
Жизненный цикл вызова Claude Code в GitLab CI/CD: от события до результата в репозитории

Базовая установка в .gitlab-ci.yml

GitLab CI/CD не умеет «скачать action» — вы сами устанавливаете Claude в before_script. Рекомендуемый базовый шаблон:

stages:
  - ai

claude:
  stage: ai
  image: node:24-alpine3.21
  rules:
    - if: '$CI_PIPELINE_SOURCE == "web"'
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
  variables:
    GIT_STRATEGY: fetch
  before_script:
    - apk update
    - apk add --no-cache git curl bash
    - curl -fsSL https://claude.ai/install.sh | bash
  script:
    # GitLab MCP Server (если настроен) — даёт доступ к API GitLab
    - /bin/gitlab-mcp-server || true
    - >
      claude
      -p "${AI_FLOW_INPUT:-'Проанализируй изменения и предложи правки'}"
      --permission-mode acceptEdits
      --allowedTools "Bash Read Edit Write mcp__gitlab"
      --max-turns 10
      --max-budget-usd 3.00

Аутентификация. Зайдите в Settings → CI/CD → Variables, добавьте ANTHROPIC_API_KEY с флагами «Masked» и «Protected». Claude Code подхватывает переменную автоматически — никакого явного --api-key не нужно.

Образ. node:24-alpine3.21 — официально рекомендованный образ. Alpine требует явной установки git и bash через apk, иначе агент упадёт при попытке работать с репозиторием.

Check yourself
В `before_script` образа `node:24-alpine3.21` добавили `curl` и установили Claude. Запустили пайплайн — агент упал с ошибкой при попытке читать файлы репозитория. Что забыли установить?

Переменные AI_FLOW_*: контекст из тредов

Когда пайплайн запускается через webhook (например, кто-то написал @claude в комментарии к MR), контекст передаётся через специальные переменные:

  • AI_FLOW_INPUT — текст запроса (что написал пользователь)
  • AI_FLOW_CONTEXT — идентификатор MR, issue или треда
  • AI_FLOW_EVENT — тип события (note, merge_request, и т.д.)

В script-блоке это выглядит так:

# Логируем контекст для отладки
echo "Запрос: $AI_FLOW_INPUT"
echo "Контекст: $AI_FLOW_CONTEXT, событие: $AI_FLOW_EVENT"

claude -p "$AI_FLOW_INPUT" \
  --allowedTools "Bash Read Edit Write mcp__gitlab" \
  --permission-mode acceptEdits

Если AI_FLOW_INPUT не задан (ручной запуск через UI), используйте дефолт через bash-подстановку: ${AI_FLOW_INPUT:-'Дефолтная задача'}.

Три паттерна автоматизации

Паттерн 1: Автоматическое ревью при открытии MR.

Запускается на событие merge_request_event, передаёт диффы через stdin:

mr-review:
  stage: ai
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      when: always
  image: node:24-alpine3.21
  before_script:
    - apk add --no-cache git curl bash
    - curl -fsSL https://claude.ai/install.sh | bash
  script:
    - >
      git diff origin/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}...HEAD
      | claude -p
      "Это diff Merge Request. Найди баги, проблемы безопасности и
       нарушения code style. Прокомментируй конкретные строки."
      --output-format json
      --max-turns 5
      --max-budget-usd 2.00
      | tee review.json
    - jq -r '.result' review.json
  artifacts:
    paths: [review.json]
    expire_in: 7 days

Паттерн 2: Scheduled-обслуживание кодовой базы.

Раз в неделю — обход устаревших TODO и потенциальных улучшений:

weekly-audit:
  stage: ai
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
  image: node:24-alpine3.21
  before_script:
    - apk add --no-cache git curl bash
    - curl -fsSL https://claude.ai/install.sh | bash
  script:
    - >
      claude --bare
      -p "Найди все TODO-комментарии старше месяца, проанализируй
          их актуальность и создай список рекомендаций."
      --allowedTools "Read,Bash"
      --output-format json
      --max-turns 8
      --no-session-persistence
      | jq -r '.result' > weekly-report.md
  artifacts:
    paths: [weekly-report.md]

Паттерн 3: Автоматические правки по запросу.

Через web-триггер с передачей AI_FLOW_INPUT:

auto-fix:
  stage: ai
  rules:
    - if: '$CI_PIPELINE_SOURCE == "web"'
  image: node:24-alpine3.21
  before_script:
    - apk add --no-cache git curl bash jq
    - curl -fsSL https://claude.ai/install.sh | bash
    # Настройка git для коммитов от агента
    - git config user.email "claude-bot@example.com"
    - git config user.name "Claude Bot"
  script:
    - >
      claude
      -p "${AI_FLOW_INPUT}"
      --permission-mode acceptEdits
      --allowedTools "Bash Read Edit Write"
      --max-turns 15
      --max-budget-usd 5.00
    # Коммит и push результатов
    - git add -A && git commit -m "fix: automated changes by Claude" || echo "Нет изменений"
    - git push origin HEAD:${CI_COMMIT_REF_NAME}
Check yourself
Вы запускаете scheduled-пайплайн раз в неделю для анализа кодовой базы. Агент должен только читать файлы — писать ничего не нужно. Какие два флага вы добавите, чтобы ускорить запуск и исключить случайные записи?

--bare: ускорение старта в CI

По умолчанию claude -p читает CLAUDE.md, хуки, плагины, MCP-серверы из рабочей директории. В CI это часто лишнее и замедляет запуск.

Флаг --bare отключает всё автообнаружение: CLAUDE.md, хуки, плагины, MCP-серверы, auto memory. Остаётся только то, что вы явно передали через флаги. Результат: воспроизводимые, быстрые запуски — поведение не зависит от того, что случайно лежит в репозитории.

# Без --bare: читает всё из .claude/
claude -p "задача" --allowedTools "Read"

# С --bare: только явно переданное
claude --bare -p "задача" --allowedTools "Read" --append-system-prompt "Ты лаконичный ревьюер."

> Официальная документация отмечает: --bare станет дефолтным для -p в будущих версиях. Рекомендуется явно его использовать сейчас.

Есть один нюанс: --bare также отключает чтение CLAUDE.md. Если контекст проекта нужен, передайте его через --append-system-prompt-file ./CLAUDE.md.

Enterprise: Bedrock и Vertex AI

Для корпоративных сред с требованиями к data residency — Claude Code поддерживает те же провайдеры, что и GitHub Actions. Вместо ANTHROPIC_API_KEY используется OIDC-аутентификация:

  • Amazon Bedrock: GitLab OIDC → IAM роль через aws sts assume-role-with-web-identity, временные credentials в переменных среды. Модели с региональным префиксом: us.anthropic.claude-sonnet-4-6.
  • Google Vertex AI: Workload Identity Federation, без хранения ключей. Переменные GCP_WORKLOAD_IDENTITY_PROVIDER и GCP_SERVICE_ACCOUNT.

Оба варианта требуют ручной настройки — quickstart через one-liner не работает. Подробные YAML-примеры есть в официальной документации GitLab.

Практические соображения

Стоимость. В отличие от GitHub Actions с фиксированной стоимостью ревью, в GitLab вы платите и за runner-минуты, и за токены API отдельно. --max-budget-usd — ваш главный предохранитель. Запуск на каждый push в MR быстро накапливает расходы; ограничивайте триггеры через rules.

Параллельные пайплайны. Настройте interruptible: true на job-уровне, чтобы новый push отменял предыдущий запуск агента:

claude:
  interruptible: true
  # ...

Логи. Флаг --debug в CI — ваш лучший друг при отладке. Также добавьте --output-format json и сохраняйте артефакты: total_cost_usd в JSON-ответе позволяет отслеживать затраты по каждому запуску без открытия dashboard.

CLAUDE.md в репозитории. Без --bare агент читает его и следует правилам. Это главный способ передать стандарты кода, запрещённые паттерны и специфику проекта — так же, как при локальном запуске. Подробнее — в статье CLAUDE.md и система памяти.

Безопасность. ANTHROPIC_API_KEY — всегда masked переменная. Изменения агента идут через MR, так что команда видит каждый диф и применяются правила branch protection. О рисках bypassPermissions в публичных репозиториях — в Модель разрешений, безопасность и доверие.


Quick recall
Что отключает флаг `--bare` при запуске Claude в CI?
Quick recall
Как передать ANTHROPIC_API_KEY в GitLab CI/CD без явного флага?
Quick recall
Что происходит, когда запускается `claude -p "задача"` в CI/CD-пайплайне?

See also