Каждый репозиторий накапливает структурированные данные, которые кто‑то в конечном итоге понадобится в виде документа: изменения в релизе, участники года, инвентарь API, список открытых рисков. Данные уже находятся в JSON; недостающий шаг — отформатированный PDF или Word‑файл, который клиент, аудитор или менеджер действительно откроет. С запущенным локально рядом с Claude Code GroupDocs.Assembly.Mcp (claude mcp add с dnx GroupDocs.Assembly.Mcp --yes), агент заполняет Word‑шаблон, хранящийся в репозитории, из JSON‑файла в репозитории и записывает PDF, без того, чтобы кто‑то форматировал таблицу:

Сгенерировать PDF с примечаниями к выпуску 4.2.0 из data/release-4.2.0.json с использованием templates/release-notes.docx, а также сертификат вклада для каждого участника из data/contributors-2026.json.

Пошаговая версия с конфигурацией и устранением неполадок находится в документации: Как сгенерировать PDF или Word‑отчёт из JSON‑данных в репозитории с помощью Claude Code.

Почему бы не позволить коду‑агенту писать документ?

Код‑агенты очень хороши в создании данных, но довольно плохи в создании документов. Попросите их создать «примечания к выпуску в виде PDF», и они напишут файл Markdown, затем скрипт, который его преобразует, затем отладят шрифты скрипта. В следующем релизе они сделают это снова, немного иначе. Результат выглядит так, как по умолчанию выводит библиотека конвертации, а не как документы, которые отправляет ваша компания.

Шаблон фиксирует внешний вид и помещает его под контроль версий. templates/release-notes.docx — обычный Word‑файл с логотипом, стилями заголовков и таблицей, плюс несколько тегов <<…>>. Тот, кто отвечает за макет, редактирует его в Word; агент никогда его не трогает. JSON генерируется вашими инструментами релиза или агентом из git log, и это та часть, в которой код‑агент справляется хорошо.

Это также делает работу проверяемой. Pull request, изменяющий data/release-4.2.0.json, показывает точно, какие изменения появятся в примечаниях к выпуску, строка за строкой, в diff, который рецензент может прочитать за минуту. Pull request, изменяющий сгенерированный PDF, ничего не показывает. Хранение данных и макета как отдельных, версионированных файлов и рассмотрение документа как того, что вы рендерите из них, — та же идея, что и разделение исходного кода и артефактов сборки, и она применима к документам по тем же причинам.

Как выглядит репозиторий

repo/
  data/
    release-4.2.0.json       {"release":{...}, "changes":[...4 items]}
    contributors-2026.json   {"contributors":[...3 items]}
  templates/
    release-notes.docx       <<[release.Version]>>, <<foreach [c in
                             changes]>> table row, counts
    certificate.docx         <<[contributor.Name]>> ...
  out/                       GROUPDOCS_MCP_OUTPUT_PATH, in .gitignore
        |
        |  Claude Code -> GroupDocs.Assembly MCP server (local, stdio)
        v
  release-notes-4.2.0.pdf    pnair.pdf  tvarga.pdf  mrossi.pdf

Вызовы

Сначала агент проверяет, что ожидает шаблон, чтобы он мог сообщить, чего не хватает в JSON:

-> get_template_fields {"template":{"filePath":
     "repo/templates/release-notes.docx"}}
<- { "dataSourceNames": [ "release", "changes" ],
     "fields": [ "release.Product", "release.Version", "release.Date",
                 "changes[].Type", "changes[].Title",
                 "changes[].PullRequest", "changes[].Author" ] }

Затем один вызов рендерит его:

-> assemble_document {"template":{"filePath":
     "repo/templates/release-notes.docx"},
     "data":{"filePath":"repo/data/release-4.2.0.json"},
     "format":"pdf","outputName":"release-notes-4.2.0.pdf"}
<- Assembled 'release-notes.docx' with 'release-4.2.0.json' (JSON
   object) as PDF
   Saved to: .../release-notes-4.2.0.pdf

Строка таблицы шаблона повторяется один раз на каждое изменение, а её последняя строка подсчитывает количество изменений и уникальных авторов с помощью changes.Count() и changes.Select(c => c.Author).Distinct().Count(). Эти числа берутся из данных во время рендеринга, а не от агента.

Сертификаты представляют собой разветвление: один PDF на каждый элемент массива contributors, названный по идентификатору участника:

-> assemble_per_record {"template":{"filePath":
     "repo/templates/certificate.docx"},
     "data":{"filePath":"repo/data/contributors-2026.json"},
     "recordsPath":"contributors","fileNameField":"Handle",
     "format":"pdf"}
<- Assembled 3 of 3 document(s) from 'certificate.docx' with
   'contributors-2026.json', one per record (each record as
   'contributor'), as PDF.
   Saved to:
   .../pnair.pdf
   .../tvarga.pdf
   .../mrossi.pdf

recordsPath указывает серверу, где находится массив, когда JSON‑файл является объектом, что обычно так выглядит у реальных файлов данных.

Делайте это привычкой, а не подсказкой

Агенты следуют инструкциям проекта о том, когда использовать инструмент. Пара строк в CLAUDE.md или AGENTS.md превращают это в конвенцию:

Documents for people (release notes, reports, certificates) are generated
with the groupdocs-assembly MCP server from templates/*.docx and data/*.json.
Call get_template_fields first; never edit a template. Generated files land
in out/, which is in .gitignore. Dates in JSON as yyyy-MM-ddTHH:mm:ss.

Держите выводы вне git. По умолчанию сервер пишет рядом со своей папкой хранилища; задайте GROUPDOCS_MCP_OUTPUT_PATH в регистрации сервера в папку out/ репозитория и добавьте эту папку в .gitignore. JSON и шаблон являются исходными; PDF — артефакт сборки, регенерируемый за секунды, и его коммит приводит лишь к диффам, которые никто не может просмотреть.

Честные ограничения

  • Режим оценки: каждый PDF начинается с “Evaluation Only. Created with GroupDocs.Assembly 26.7…”. Подходит для проб, но лицензируйте сервер, прежде чем что‑то покинет команду.
  • Шаблоны являются доверенным вводом. Теги изображений и документов загружают пути и URL, которые возвращают их выражения, поэтому рассматривайте шаблон из pull request как код и предоставьте серверу одну папку хранилища.
  • Даты: записывайте их как 2026-11-03T00:00:00 и форматируйте в шаблоне (<<[release.Date]:"d MMMM yyyy">>). Строка только с датой смещалась на день на машине UTC+2 в нашем тесте; Docker‑образ работает в UTC.
  • Генерация по записи читает только JSON, а maxDocuments (по умолчанию 100) останавливает неожиданно большой массив до записи чего‑либо.
  • get_template_fields статичен: значения, вычисленные внутри проекций Select или GroupBy, не учитываются.

FAQ

Может ли Claude Code сгенерировать PDF из JSON в моём репозитории без облачного сервиса?
Да. MCP‑сервер работает локально как дочерний процесс Claude Code и читает шаблон и JSON из указанной вами папки.

Можно ли запустить это в CI?
Сервер — это MCP‑сервер, поэтому ему нужен MCP‑клиент: Claude Code в безголовом режиме или любой агент‑раннер. Docker‑образ (ghcr.io/groupdocs-assembly/assembly-net-mcp) — удобный вариант для конвейера.

Word или PDF?
Любой. Если опустить format, вывод будет DOCX, как шаблон; "format":"pdf" выдаёт PDF. get_supported_formats перечисляет все целевые форматы для каждого шаблона.

Углубиться