AI-разработка

Как CLI cf от Cloudflare дает ИИ-агенту искать команды в JSON и вызывать API (2026)

Около 15 мин

Агенту не нужно помнить больше 2900 команд. Он ищет одной фразой, читает поля API, которые команда отправит, и только потом запускает ее. Результат — JSON с отступами на стандартном выводе. Ход работы и ошибки идут в стандартный поток ошибок. Модель только заполняет аргументы. API Cloudflare вызывает cf.

Коротко перед чтением

Объект Публичные факты на 2026-10-13 Как этим пользуется агент
cf Открытая бета 28 сентября. Покрывает весь API. В документации больше 2900 команд. Ставится через npm JSON по умолчанию. Флаг --json не нужен
cf cli search Локальный поиск. Вход не нужен. Вся фраза в кавычках. Не больше пяти совпадений, лучшее первым Брать только command и summary. Пока не выполнять
cf schema Описывает HTTP сгенерированной команды: метод, путь, параметры, поля тела Сначала обязательные поля. deploy и похожие команды — через --help
Результат Документация от 29 сентября: JSON всегда с отступами. Неинтерактивное удаление без --force может напечатать Aborted. в stderr и все равно завершиться с кодом 0 Сначала JSON на stdout, потом код выхода

В анонсе было: красиво для людей и сжато для агентов. Документация от 29 сентября говорит, что JSON с отступами независимо от того, терминал ли stdout. Публичная проверка 1.0.0-beta.5 8 октября тоже не увидела сжатый вывод. Парсер следует документации. orders.example.test вымышлен.

Агент управляет Cloudflare тремя шагами JSON, а не заучиванием команд

Cloudflare опубликовал cf 28 сентября. В анонсе сказано, что в марте агенты составляли около четверти использования Wrangler, а за неделю до запуска — 48%. У Wrangler было около 280 команд, собранных вручную, и они не покрывали весь API. Новая CLI генерируется из OpenAPI. Документация от 29 сентября называет больше 2900 команд. Установка: npm install --global cf. cf auth login требует, чтобы человек подтвердил страницу в браузере. Для запуска без присмотра задают CLOUDFLARE_API_TOKEN: он важнее сохраненного входа. Токен в репозиторий не кладут. В примере только sk_demo_not_real.

  • Поиск: cf cli search "create D1 database". Кавычки остаются. Поиск локальный и не трогает аккаунт.
  • Проверка: cf schema d1 create перечисляет поля HTTP, которые уйдут. Перед реальным изменением добавляют --dry-run. Пробный запуск не требует учетных данных.
  • Запуск: на стандартном выводе только JSON-результат. Выбранная зона, ошибки и Aborted. идут в поток ошибок.

Это не агент, который нажимает страницы. Как каталог плагина кладет MCP-сервер в mcp.json: договор каталога Agent Plugins 1.0.0. Как выглядит MCP tools/call: как coding agent вызывает MCP. Здесь только JSON, который cf отдает агенту.

Документация от 29 сентября показывает первые два совпадения в таком виде. Поля только command и summary:

[
  {
    "command": "cf d1 create",
    "summary": "Create D1 Database"
  },
  {
    "command": "cf d1 update",
    "summary": "Update D1 Database"
  }
]

Без кавычек каждое слово после первого становится неизвестной командой. Корневой и групповой --help сначала отправляет агента в поиск. Собственный --help команды — обычный текст, не этот массив. Если команды нет, CLI показывает близкие имена. Это тоже не результат поиска.

Сначала прочитать запрос, который уйдет, потом одну вернувшуюся страницу

cf schema покрывает только сгенерированные команды API. Для cf deploy нужен --help. Документированные ключи: operationId, httpMethod, path, pathParams, queryParams, hasRequestBody, requestBodyFields. Параметры используют имена API, например account_id. Поля тела — имя опции и описание. Если список неполный, целое тело передают через --body. Ниже те же ключи как пример: имя хоста вымышлено, это не снимок с продакшена:

{
  "operationId": "dns-records-create",
  "httpMethod": "POST",
  "path": "/zones/{zone_id}/dns_records",
  "pathParams": [
    { "name": "zone_id", "type": "string", "required": true }
  ],
  "queryParams": [],
  "hasRequestBody": true,
  "requestBodyFields": [
    { "name": "type", "type": "string", "required": true, "description": "Record type" },
    { "name": "name", "type": "string", "required": true, "description": "Record name" },
    { "name": "content", "type": "string", "required": true, "description": "Record content" }
  ]
}

Обязательные поля проходят порог до запуска. Почему порог нельзя оставить только в промпте: зачем ИИ нужен JSON Schema. Стандартный вывод команды-списка — JSON-массив из одной страницы. Флаги постраничности у команд разные. Изменение без данных оставляет stdout пустым. Сырые байты объекта R2 или изображения модели идут на stdout как есть, не объектом. Вымышленная страница DNS:

[
  {
    "id": "rec_demo_1042",
    "type": "TXT",
    "name": "orders.example.test",
    "content": "demo-pass"
  }
]

Имена полей зависят от команды. Парсер сначала убеждается, что это массив, и берет id или name из schema этой команды. Не стоит ждать оболочку success на каждой странице.

Не склеивать стандартный вывод, поток ошибок и код выхода в один успех

Агенту легко сжать три сигнала в один:

Что видно Что это значит
JSON с отступами на stdout Это и есть результат. Документация говорит: с отступами, терминал stdout или нет. Фразу анонса про сжатый вывод для агентов не стоит брать текущим контрактом разбора.
Выбранная зона, ошибки, Aborted. В stderr. Разрушительная команда без --force в неинтерактивном сеансе может напечатать только Aborted. и все равно завершиться с кодом 0.
cf workers delete --force У части команд --force одновременно параметр API. Он может удалить Worker, на который еще ссылаются другие. Перед разрешением смотрят schema.
Репозиторий только с wrangler.jsonc Пока нет cloudflare.config.ts, агенту нельзя запускать cf dev, cf build и cf deploy. Сначала cf migrate --dry-run.

Проект с уже существующей конфигурацией Wrangler остается на Wrangler. Остальные задачи Cloudflare идут через cf. Эту фразу кладут в AGENTS.md или CLAUDE.md. --local покрывает только часть KV, D1 и R2. У cf d1 query нет локального аналога: команда возвращает ошибку, а не тихо вызывает боевой API.

Шесть шагов, прежде чем агент изменит боевой ресурс

Не начинать с вставки токена в промпт:

  1. Человек завершает cf auth login. CLOUDFLARE_API_TOKEN только для запуска без присмотра. Токен не кладут в JSON команды.
  2. Искать в кавычках. Вся фраза — один аргумент. Сначала прочитать не больше пяти значений command.
  3. Запустить cf schema. Смотреть required. Если список неполный, перейти на --body и документацию API.
  4. Сначала --dry-run. Он печатает JSON запроса, ничего не отправляет и не требует учетных данных. Проверить, что в пути демо-значение вроде zone_demo_1042.
  5. Разбирать только stdout. Пустой вывод значит, что это изменение не вернуло данных. У разрушительной команды смотреть, нет ли Aborted. в stderr.
  6. Проект Wrangler сначала переносят. Без cloudflare.config.ts не деплоить. Если в сгенерированном файле остался TODO(@cloudflare), сборка упадет.

После открытой беты Wrangler еще 18 месяцев на сопровождении. Оба инструмента могут стоять рядом. В одном проекте агент не должен накрывать старую конфигурацию через cf deploy.

Перед разрешением записи развернуть три JSON

Сбой чаще всего из поиска без кавычек, schema, которое не совпало с результатом, или кода 0, прочитанного как уже сделанное удаление.

  • Массив поиска и schema форматировать, затем проверка Schema: есть ли каждое required: true внутри requestBodyFields.
  • Через извлечение JSONPath вынуть $[0].command, $.httpMethod и $.path.
  • Сравнить через JSON Diff запрос --dry-run и вернувшуюся страницу. Недостающие поля заполнить раньше, чем менять промпт.
  • Если в stderr есть Aborted., удаления не было.
  • Зону, токен и идентификатор аккаунта не вставлять в публичный форматтер. JSONSort работает локально в браузере.

Когда три куска совпали, агент вызывает API, а не угадывает команду. Сами отступы ошибкой не являются.

Частые ошибки

  • Ждать сжатый JSON из-за анонса. Текущая документация говорит: всегда с отступами. Проверка beta.5 8 октября не увидела более короткий вывод только потому, что обнаружен агент.
  • Искать без кавычек. Второе слово становится неизвестной командой. Результат поиска и список близких имен — не один и тот же JSON.
  • Читать код 0 как успешное удаление. Без --force неинтерактивный запуск мог только прерваться. Смотреть и stderr.
  • Запускать cf deploy в репозитории, где есть только wrangler.jsonc. Может появиться новая конфигурация, а старая останется в стороне. Сначала dry-run миграции.
  • Класть API-токен в промпт или в JSON, который попадет в коммит. Без присмотра только переменная окружения. В примере не использовать настоящий токен.
  • Описывать cf как агента, который сам нажимает браузер. Вход подтверждает человек. Дальше вызовы API — это JSON от CLI, а не клики по странице.

Вопросы

Нужно ли агенту по-прежнему добавлять --json к каждой команде?

Нет. Результат cf по умолчанию — JSON на stdout. Флаг --json и таблицы относятся к Wrangler. По документации от 29 сентября этот JSON с отступами. Сжатый формат ждать не нужно.

Использует ли cf cli search мой аккаунт?

Нет. Поиск локальный и не требует учетных данных. Он возвращает не больше пяти объектов, у каждого есть command и summary. Ресурс меняет уже следующая команда.

Отсутствие JSON — это ошибка?

Не всегда. Изменение, которое не возвращает данных, оставляет stdout пустым. Ошибка — это ненулевой код выхода, текст лежит в stderr. Прерванное удаление пишет Aborted. в stderr и может завершиться с кодом 0.

Нужно ли сегодня переводить проект Wrangler на cf?

Деплой не обязан смениться в тот же день. Пока есть wrangler.jsonc или wrangler.toml, разработка, сборка и деплой остаются на Wrangler. Переход на cloudflare.config.ts идет через cf migrate, сначала с --dry-run. После открытой беты Wrangler еще 18 месяцев на сопровождении.

Что делать, если requestBodyFields неполный?

Документация прямо говорит: у части команд requestBodyFields неполный или пустой. Тогда целое тело отправляют через --body и сверяют с документацией API. Пустой список не значит, что у API нет тела.

Итог

cf — это путь, которым ИИ-агент вызывает API Cloudflare через JSON. Поиск дает имя команды, schema — поля, которые уйдут, stdout — одну страницу результата. Разбирайте JSON с отступами и отделяйте stderr от кода выхода.

Сначала убедитесь, что cf d1 create пришел из массива поиска, zone_id — из schema, а orders.example.test есть только в демо-результате. Когда три места совпали, боевой ресурс можно менять.

Дальше по теме

История: Первая публикация