Справочник полей сервиса
Каждое поле, допустимое в workspace/services/<name>/service.yml, плюс вложенные блоки (ports, hosts, icon, info, configs, dirs, cli, status, render, generated).
Содержание
Заголовок раздела «Содержание»- Поля сервиса верхнего уровня
- Поле
ports - Поле
hosts - Поле
icon - Блок
info - Поле
configs - Поле
dirs - Блок
cli - Блок
status - Блок
render - Блок
generated - Блок
bridge
Терминология host vs internal: Поля, оканчивающиеся на *_internal или использующие суффиксное соглашение (например, dir для хоста, dir_internal для контейнера), относятся к путям: host-сторона работает на вашей машине, internal-сторона — точка монтирования в контейнере. То же различие применяется к портам и именам хостов: ports.http задаёт имя порта контейнера и хостовый порт, на котором он должен появиться; hosts.main — это имя, под которым контейнер резолвится.
Поля сервиса верхнего уровня
Заголовок раздела «Поля сервиса верхнего уровня»| Поле | Тип | Обязательно | Допустимо для | Описание |
|---|---|---|---|---|
type | string | да | app / tool / infra | Дискриминатор — выбирает список разрешённых полей для записи. |
container | string | нет (по умолчанию имя папки) | все | Имя compose-сервиса (по умолчанию имя папки). Команды для одного сервиса (logs, stop, restart, reset --service) находят запущенный контейнер по меткам compose (проект + сервис), поэтому пинить container_name в compose-файле под это имя не нужно — дефолтное именование compose <project>-<service>-<index> работает как есть. |
required | bool | нет | все | Если true, сервис всегда включён; оверлей не может его выключить. |
compose | list | нет | все | Дополнительные файлы оверлея compose, активируемые при включении сервиса. |
ports | map[string]int | map[string]{port,scheme} | нет | все | Именованные порты контейнера. Краткая форма (int) или развёрнутая {port, scheme}. См. Поле ports. |
hosts | map[string]string | нет | все | Именованные имена хостов. См. Поле hosts. |
icon | string | нет | все | Визуальный индикатор — эмодзи или символ, используемый в дашборде dwe info. Если опущен, используется значение по умолчанию для типа: type: app → 📦, type: tool → 🔧, type: infra → 🧱. См. Поле icon. |
info | block | нет | все | Метаданные отображения для дашборда info — переопределение заголовка, выбор ключа host/port и подпути. См. Блок info. |
depends_on | list | нет | app / infra | Упорядоченная зависимость от других сервисов (влияет на порядок deploy). Цель type: tool отклоняется при загрузке. |
status | list | нет | все | Пользовательские колонки для таблицы dwe status apps / tools / infra по типу — см. Блок status. |
on_enable | block | нет | app / tool / infra | Хуки жизненного цикла при включении сервиса. См. Примеры — жизненный цикл переключения. |
on_disable | block | нет | app / tool / infra | Хуки жизненного цикла при выключении сервиса. |
notes | block | нет | app / tool / infra | Человекочитаемые подсказки, отображаемые в плане команд services enable/disable. |
dir | string | да (без extends) | app | Путь к hub-каталогу сервиса на хосте. |
dir_internal | string | нет | app | Точка монтирования hub в контейнере. |
work_dir_internal | string | нет | app | Рабочий каталог по умолчанию для exec/run внутри контейнера. |
extends | string | нет | app | Наследует поля из другой записи type: app. Межтиповой extends отклоняется. См. Наследование. |
configs | list | нет | app | ⚠️ Устарело — механизм копирования; мигрируйте на render.config. См. Поле configs. |
dirs | list | нет | app | Дополнительные каталоги относительно hub — см. Поле dirs. |
cli | block | нет | app | Значения по умолчанию для dwe shell — см. Блок cli. |
render | block | нет | app | Вложенная политика рендера шаблонов (ide / ai / git / config) — см. Блок render. |
generated | block | нет | app | Per-service значения, генерируемые сервисом, которые DWE собирает и переигрывает — см. Блок generated. |
bridge | block | нет | все (по умолчанию выкл. — строго opt-in) | Opt-in host-моста — монтирует shim dwe в контейнер сервиса, чтобы dwe работал изнутри него. См. Блок bridge. |
Поле ports
Заголовок раздела «Поле ports»ports: всегда карта от имени порта к порту контейнера. Сервисам с одним портом требуется выбранное имя (рекомендация: http для веб, tcp для сырого TCP, ролевые имена вроде mysql / amqp для infra). Значения портов определяются в workspace/services/<name>/service.yml; оверлеи workspace/local.yml могут переназначать отдельные записи — см. поведение глубокого слияния в Поведение загрузки.
ports: — декларативные метаданные: сам по себе этот блок ничего не пробрасывает. Его читают dwe status, dwe info и preflight ports_free, но реальный биндинг живёт в вашем compose-файле, который получает значение через парное правило exports.env (from: services.<name>.ports.http) в workspace/defaults.yml. Порт, объявленный здесь без такого правила, существует только для отображения; dwe validate предупреждает о нём. См. exports.env.
Каждая запись порта принимает две равноценные формы:
- Краткая (int) — номер порта. Применяется схема уровня сервиса (из
info.schemeс фолбэком наruntime.use_https). - Развёрнутая (mapping) —
{port: <int>, scheme: "http" | "https"}. Используйте, когда один сервис говорит по разным схемам на разных портах (например, API отдаёт HTTP на3000и HTTPS-админку на9443).
type: infracontainer: rabbitmqports: amqp: 5672 # краткая форма — без переопределения схемы admin: 15672
# workspace/services/api/service.yml — смешанные схемы внутри одного сервисаtype: appcontainer: apiports: http: 3000 # краткая: схема наследуется от info.scheme / runtime admin: # развёрнутая: этот порт всегда https, независимо от глобального флага port: 9443 scheme: httpsЗначения ограничены 1..65535 во время загрузки. Скалярные формы (ports: 80, ports: "80") отклоняются с ErrServicePortsShape. В развёрнутой форме допустимы только поля port и scheme; scheme должна быть "http" или "https" (или опущена).
Приоритет в оверлеях. Запись в workspace/local.yml может использовать любую из форм. Оверлеи мерджатся пополю с унаследованной спецификацией:
- чистый int (
http: 6000) — перекрывает только номер порта;schemeизservice.ymlсохраняется. - mapping (
http: {port: 6000}) — то же, что и чистый int (затрагивает толькоport), полезно ради единообразия с rich-формой. - mapping только со scheme (
http: {scheme: https}) — перекрывает только схему; унаследованный номер порта сохраняется. В rich-форме оверлея должно присутствовать хотя бы одно из полейport/scheme. - mapping с обоими полями (
http: {port: 6000, scheme: https}) — перекрывает оба.
scheme: null трактуется как «нет переопределения» (эквивалентно отсутствию ключа).
Эффективная схема. Когда dwe рендерит URL для записи порта, он выбирает схему по цепочке приоритета:
- per-port
scheme:(развёрнутая форма на этой записи); - схема уровня сервиса
info.scheme; - глобальная
runtime.use_https(true→https,false→http).
Это также доступно шаблонам через метод ServiceConfig.EffectiveScheme — см. Шаблоны. Для dot-path-доступа (from: / ${...}) per-port схемы доступны под соседним ключом services.<n>.port_schemes.<port-name> (string), который присутствует только у сервисов, фактически использующих переопределение.
URL’ы через reverse-proxy (port_via). Разрешение схемы для проксированного URL маршрутизируемого сервиса идёт по отдельной цепочке, которая намеренно пропускает info.scheme самого прокси (иначе схема прокси «протекла» бы на каждый маршрутизируемый сервис). Цепочка такая:
info.schemeмаршрутизируемого сервиса — задаёт и схему URL, и то, какой listener прокси (httpилиhttps) будет использован;- per-port
scheme:на записи listener’а прокси; - глобальная
runtime.use_https.
Это позволяет одному общему прокси обслуживать стек со смешанными схемами. Объявите ports.http: 80 и ports.https: 443 на прокси, затем выставьте info.scheme: https на тех маршрутизируемых сервисах, для которых прокси терминирует TLS; «соседи» без переопределения останутся на http. info.scheme у самого прокси по-прежнему влияет только на его собственную строку в dwe info и не передаётся приложениям, маршрутизируемым через него.
Поле hosts
Заголовок раздела «Поле hosts»hosts: всегда карта от имени хоста к имени хоста. Симметрично с ports. Для одного имени хоста принято использовать web.
type: apphosts: web: app.localhostЗначения хостов определяются в workspace/services/<name>/service.yml; оверлеи workspace/local.yml могут переназначать отдельные записи — см. поведение глубокого слияния в Поведение загрузки.
Поле icon
Заголовок раздела «Поле icon»Необязательный эмодзи или символ Unicode, отображаемый рядом с именем сервиса в дашборде dwe info при рендеринге блоков auto-urls.
type: appicon: "📦"Если опущен, используется значение по умолчанию на основе типа:
type | Иконка по умолчанию |
|---|---|
app | 📦 |
tool | 🔧 |
infra | 🧱 |
Иконки рассматриваются как непрозрачный пользовательский контент — эмодзи, соединённые ZWJ (глифы семей, модификаторы профессий, вариации цвета кожи), поддерживаются, но длина не валидируется. Иконка появляется только в выводе dwe info; в других местах не используется.
⚠️ Избегайте эмодзи с
Emoji_Presentation=No. Кодовые точки вроде🛢(U+1F6E2),🗄(U+1F5C4) и⚙(U+2699) являются «text-default» — они рендерятся как цветной эмодзи только за VS-16 (U+FE0F), и многие комбинации терминалов и шрифтов на macOS и Linux игнорируют этот хинт и отрисовывают их в 1 ячейке вместо 2. Lipgloss измеряет их как 2 ячейки, поэтому таблицы status / info недозаполняются и каждая колонка справа от иконки сдвигается.
dwe validateпомечает такие иконки (warning, областьconfig.icons) и предлагает безопасные замены из подобранной карты. Во время рендера runtime полностью отбрасывает неоднозначные иконки, а не позволяет им сломать выравнивание колонок — они просто не появятся в дашборде, таблице status или меню переключения. Та же оговорка применяется к иконкам вinfo.paths[].iconи пользовательским иконкамauto-hosts/auto-urlsвworkspace/info.yml.Предпочитайте кодовые точки, являющиеся эмодзи по умолчанию — например,
📦,🧱,🐳,📚,💾,🔧,🧰— или придерживайтесь однотиповых ASCII / символов псевдографики.
Блок info
Заголовок раздела «Блок info»Необязательные метаданные для рендеринга этого сервиса в дашборде dwe info.
type: appinfo: title: "Main Application" primary_host: web primary_port: http paths: - name: "API Documentation" path: /api/docs icon: "📖" - name: "Profiler" path: /?SPX_KEY=dev icon: "⚡"| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
title | string | title-case(имя-папки) | Отображаемое имя сервиса в дашборде (например, "Main Application"). Заменяет значение по умолчанию, выведенное из имени папки. |
primary_host | string | web | Какой ключ из hosts показать в основной строке URL (например, console для сервиса с несколькими хостами). |
primary_port | string | http | Какой ключ из ports показать в основной строке URL (например, console для сервиса с несколькими портами). |
scheme | string | — | Переопределение схемы URL уровня сервиса ("http" или "https"). Побеждает глобальную runtime.use_https, уступает per-port scheme: в развёрнутой форме ports. |
paths | list | — | Упорядоченный список подпутей под основным URL. См. Записи info.paths ниже. |
Когда использовать info.scheme. Установите, если сервис говорит по одной фиксированной схеме, отличной от дефолта проекта — например, dev-сервер Vite с @vitejs/plugin-basic-ssl слушает https://localhost:5173, а остальная часть проекта остаётся на http:// (OAuth-колбэки, обычный dev-бэкенд). Пустой info.scheme означает фолбэк на runtime.use_https, что корректно для проектов с единообразной HTTP- или HTTPS-конфигурацией.
Записи info.paths
Заголовок раздела «Записи info.paths»Каждая запись в списке paths объявляет именованный подпуть относительно основного URL сервиса.
paths: - name: "API Documentation" path: /api/docs icon: "📖" - name: "Profiler" path: /?SPX_KEY=dev| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
name | string | да | Отображаемое имя пути (например, "API Documentation"). Должно быть непустым и уникальным в списке paths сервиса. |
path | string | да | Путь URL относительно основного хоста сервиса (должен начинаться с /). Пример: /api/docs, /admin, /?SPX_KEY=dev. |
icon | string | нет | Необязательный эмодзи или символ, добавляемый перед именем пути. По умолчанию 🔗, если опущен. |
Сервисы без блока info всё равно включаются в блоки дашборда auto-urls (если их типы include совпадают) и рендерят свой основной URL; они просто не добавляют пользовательский заголовок или подпути.
Поле configs
Заголовок раздела «Поле configs»⚠️ Устарело. Механизм копирования
configs:(и подполеmountpoint) вытесненrender.config+ блокомgenerated. Он продолжает работать, ноdwe validateвыдаёт предупреждение, и при каждом шаге копирования один раз срабатывает runtime-уведомление об устаревании. Новым проектам следует рендерить конфиги из шаблонных паков; см. render config для миграции.
Перечисляет конфигурационные файлы, копируемые в hub сервиса при deploy.
configs: - .env # сокращение: копирует src в configs/.env, монтирует по умолчанию - file: .env mountpoint: src/.env # явное место назначения внутри контейнера| Поле | Описание |
|---|---|
file (или сокращение-строка) | Имя исходного файла (относительно configs/services/<service>/) |
mountpoint | ⚠️ Устарело. Путь относительно dir сервиса (например, src/.env), где файл «трогается» после копирования. Используется билтином service_configs_copy для создания заглушки под вложенные файловые bind-монтирования Docker Desktop virtiofs. Необязательно. |
Исходный каталог configs/services/<service>/ принадлежит проекту и коммитится в git; целевой services/<service>/configs/ создаётся при deploy и попадает в gitignore.
Поле dirs
Заголовок раздела «Поле dirs»Дополнительные каталоги для создания внутри hub-каталога сервиса помимо обязательного src.
dirs: - logs - home - runtime- Пути относительны
dirсервиса (например,./services/main/logs). - Каталог
src/всегда создаётся и здесь не перечисляется; он также защищён (skip-семантика) в режимеrecreate, поэтому исходный код никогда не стирается. - Каталог
configs/не обязателен — он создаётся лениво билтиномservice_configs_copy, когда объявлен блокconfigs:. Если он нужен заранее или должен стираться подrecreate, перечислите его явно здесь. - Когда сервис
extendsдругой, полеdirsпотомка дописывается к родительскому (дедуплицировано, сначала родитель). - Используется билтином
service_dirs_ensureво время deploy.
Блок cli
Заголовок раздела «Блок cli»Управляет тем, как dwe shell и выполнение CLI ведут себя для этого сервиса.
cli: mode: auto # auto | exec | run shell: bash user: www-data workdir: /workspace/src env: - XDEBUG_CONFIG="cli_color=1"| Поле | По умолчанию | Описание |
|---|---|---|
mode | auto | auto = exec при работающем контейнере, run при отсутствии, ошибка при остановленном; exec = всегда docker exec (ошибка, если не запущен); run = всегда docker compose run --rm |
shell | bash | Бинарь shell для вызова внутри контейнера |
user | текущий UID | Пользователь для запуска внутри контейнера |
workdir | work_dir_internal (затем dir_internal) | Рабочий каталог shell-сессии |
env | — | Дополнительные env-переменные, внедряемые в shell-сессию |
Флаги CLI переопределяют конфиг cli. Порядок приоритета (от высшего к низшему): флаги --root/--user/--shell/--env → конфиг cli → встроенные значения по умолчанию.
cli.env в форме карты vs списка
Заголовок раздела «cli.env в форме карты vs списка»cli.env принимает либо YAML-карту, либо список вида KEY=VALUE; обе формы дают одну и ту же внутреннюю карту и взаимозаменяемы.
# Форма картыcli: env: XDEBUG_CONFIG: "cli_color=1" PHP_IDE_CONFIG: serverName=dwe
# Форма спискаcli: env: - XDEBUG_CONFIG="cli_color=1" - PHP_IDE_CONFIG=serverName=dweФорма списка удобна при копировании из файла .env; форма карты дружелюбнее для наследования и переопределения отдельных ключей через extends:.
Блок status
Заголовок раздела «Блок status»Необязательный список пользовательских колонок, дописываемых к таблице status, специфичной для типа — dwe status apps для type: app, dwe status tools для type: tool, dwe status infra для type: infra (и составной dwe status по умолчанию). Каждая запись объявляет имя колонки и герметичный Go-шаблон, вычисляемый построчно против смерженного конфига.
type: appcontainer: app-maindir: ./services/mainstatus: - name: CONTAINER value: "{{ .ServiceCfg.Container }}" - name: TAG value: "{{ .Globals.baseImageTag }}"| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
name | string | да | Заголовок колонки (приводится к верхнему регистру в отрендеренной таблице). |
value | string | да | Go-шаблон, вычисляемый через tpl.Render. Герметичный — без доступа к env / FS / сети. |
Контракт данных шаблона (Go-шаблоны чувствительны к регистру):
| Путь | Источник | Регистр |
|---|---|---|
.ServiceCfg.<Field> | типизированный ServiceConfig для сервиса этой строки | PascalCase имена полей Go (.ServiceCfg.Container, .ServiceCfg.Dir) |
.Globals.<key> | cfg.Raw["globals"], если есть, иначе nil | строчные YAML-ключи (.Globals.baseImageTag) |
.Raw.<key>... | полная карта cfg.Raw | строчные YAML-ключи (.Raw.services.main.ports.http, .Raw.project.name) |
В корне данных только эти три ключа — нет алиасов .Project / .Runtime в корне. Углубляйтесь в .Raw.project.*, .Raw.runtime.*, .Raw.services.*.
Обработка ошибок: шаблон, вызвавший ошибку, рендерится в таблице как — и вносит вклад в одно агрегированное предупреждение (warning: N custom status expression(s) failed to render) в stderr. Команда всё равно завершается с кодом 0.
Порядок колонок: в пределах одного раздела status по типу (apps / tools / infra), когда несколько сервисов объявляют пересекающиеся колонки, порядок колонок в отрендеренной таблице — «первое появление» при детерминированной алфавитной итерации по сервисам этого типа. Сервисы, объявляющие меньше колонок, оставляют отсутствующие ячейки как —.
Блок render
Заголовок раздела «Блок render»Вложенный блок, управляющий тем, рендерит ли (и как именно) система файлы для этого сервиса из шаблонных паков. Содержит четыре подблока: ide, ai, git (у каждого одинаковая структура enabled / template) и config (один пин template — см. Блок render.config).
Блок render.ide
Заголовок раздела «Блок render.ide»Управляет тем, рендерит ли (и как именно) IDE-рендер конфигурационные файлы для этого сервиса из шаблонных паков.
render: ide: enabled: true # opt-in для IDE-рендера для этого сервиса template: main-debug # использовать пользовательский шаблонный пак| Поле | По умолчанию | Описание |
|---|---|---|
enabled | true для type: app; false иначе | Включить этот сервис в IDE-рендер. dwe render ide уважает эту настройку; см. Активация ниже. |
template | — | Необязательное имя каталога пользовательского шаблонного пака. Должно быть единственным ключом каталога под workspace/templates/ide/ (без разделителей пути, без .., без абсолютных путей, без ведущей .). Если опущен, рендер откатывается к пакам, специфичным для имени сервиса, затем к глобальным. Явные паки строгие: опечатка приведёт к ошибке, а не к молчаливому фоллбэку. |
Правила активации IDE
Заголовок раздела «Правила активации IDE»IDE-рендер требует одновременно активации и условий политики:
- Активация проекта: Сервис должен быть включён на уровне проекта (через трёхслойное слияние конфига; обязательные сервисы всегда включены).
- Политика IDE: Настройка
render.ide.enabledдолжна бытьtrue.
Сервис рендерится только если оба условия выполнены. Отключение любого подавляет рендер.
Политика по умолчанию: сервисы type: app по умолчанию имеют render.ide.enabled: true (opt-out); tool / infra вообще не могут нести блок render: (разрешённые поля по типу). Чтобы рендерить файлы IDE для не-app сервиса, его нужно переопределить по типу — нет per-pack обходного пути.
Разрешение шаблонного пака
Заголовок раздела «Разрешение шаблонного пака»dwe render ide ищет шаблонные паки в таком порядке; используется первое совпадение:
workspace/templates/ide/<template>/(еслиtemplateзадан) — строго: пак должен существовать, иначе рендер падаетworkspace/templates/ide/<service-name>/(еслиtemplateне задан)workspace/templates/ide/default/(финальный фоллбэк)
Когда указан явный template:, а пак не найден, рендер падает с ошибкой (ловит опечатки). Когда явный шаблон не задан и неявная цепочка исчерпывается без нахождения пака, рендер пропускается с предупреждением.
После выбора пака команда читает manifest.yml пака, чтобы определить, какие файлы рендерить и какие симлинки создавать. Манифест объявляет:
render: исходные файлы шаблонов (должны оканчиваться на.tmpl) и их пути назначенияsymlinks: относительные симлинки для создания внутри каталога сервиса (необязательно)
Все назначения относительны каталога сервиса (например, services/main/). Вложенные пути допустимы (например, .devcontainer/devcontainer.json).
Эта основанная на манифесте модель позволяет добавлять поддержку любого IDE или инструмента (.cursor/, .zed/, .envrc и т.д.) без модификации кода — добавьте файлы шаблонов и объявите их в manifest.yml.
Разрешение коллизий
Заголовок раздела «Разрешение коллизий»Когда несколько сервисов разделяют один dir (например, main и main-debug, оба указывающие на ./services/main), только самый дочерний (глубже всего в цепочке extends) сервис рендерит файлы IDE. Остальные отчитываются как пропущенные с предупреждением о коллизии.
Явная позиционная форма dwe render ide <service> трактует аргумент как якорь hub: он валидируется как реальный сервис, но затем разрешается через ту же политику коллизий. Поэтому dwe render ide main на самом деле рендерит main-debug, когда main-debug включён — полезно из per-service пайплайнов deploy, передающих каноническое имя сервиса и ожидающих результат с учётом варианта.
type: appdir: ./services/main# render.ide.enabled по умолчанию truetype: appextends: main # тот же dir, что у родителяdir: ./services/mainrender: ide: template: main-debug # использовать другой шаблонный пак# файлы IDE идут в ./services/main/ с содержимым из пака main-debug# (main-debug побеждает, потому что extends main)В этом примере dwe render ide создаёт файлы в ./services/main/ с использованием шаблонного пака main-debug и выдаёт предупреждение, что main пропущен из-за коллизии.
Разбор примера: раскладка шаблонного пака
Заголовок раздела «Разбор примера: раскладка шаблонного пака»Этот пример показывает, как организованы шаблонные паки и какие файлы получаются в каталоге сервиса.
Структура проекта:
workspace/services/ main/ service.yml main-debug/ service.ymlworkspace/templates/ide/ default/ manifest.yml .devcontainer/devcontainer.json.tmpl .vscode/settings.json.tmpl main-debug/ manifest.yml .devcontainer/devcontainer.json.tmpl .vscode/settings.json.tmpl .vscode/launch.json.tmplОпределения сервисов:
type: appdir: ./services/main# render.ide.enabled по умолчанию true; рендерит, используя пак defaulttype: appextends: maincontainer: app-main-debugdir: ./services/mainrender: ide: template: main-debug # переопределить на использование пака main-debugПосле dwe render ide:
services/main/ .devcontainer/ devcontainer.json ← отрендерено из main-debug/.devcontainer/devcontainer.json.tmpl .vscode/ settings.json ← отрендерено из main-debug/.vscode/settings.json.tmpl launch.json ← отрендерено из main-debug/.vscode/launch.json.tmplОбратите внимание, что main пропущен из-за коллизии (тот же dir, что и у main-debug), поэтому рендерится только шаблонный пак main-debug.
Блок render.ai
Заголовок раздела «Блок render.ai»Управляет тем, рендерит ли (и как именно) агентная документация hub-уровень документации для этого сервиса из шаблонных паков.
render: ai: enabled: true # opt-in для рендера агент-документации для этого сервиса template: custom-docs # использовать пользовательский шаблонный пак| Поле | По умолчанию | Описание |
|---|---|---|
enabled | true для type: app; false иначе | Включить этот сервис в вывод dwe render ai. Когда true, в hub сервиса генерируется агент-ориентированная документация. |
template | — | Необязательное имя каталога пользовательского шаблонного пака. Должно быть единственным ключом каталога под workspace/templates/ai/ (без разделителей пути, без .., без абсолютных путей, без ведущей .). Если опущен, рендер откатывается к пакам, специфичным для имени сервиса, затем к default. Явные паки строгие: опечатка приведёт к ошибке, а не к молчаливому фоллбэку. |
Правила активации агент-документации
Заголовок раздела «Правила активации агент-документации»Рендер агент-документации требует одновременно активации и условий политики:
- Активация проекта: Сервис должен быть включён на уровне проекта (через трёхслойное слияние конфига; обязательные сервисы всегда включены).
- Политика агент-документации: Настройка
render.ai.enabledдолжна бытьtrue.
Сервис рендерится только если оба условия выполнены. Отключение любого подавляет рендер.
Политика по умолчанию: сервисы type: app по умолчанию имеют render.ai.enabled: true (opt-out); не-app сервисы по умолчанию имеют false и должны подключаться явно (установите render.ai.enabled: true). Установите render.ai.enabled: false, чтобы подавить генерацию агент-документации для app-сервиса.
Разрешение шаблонного пака
Заголовок раздела «Разрешение шаблонного пака»dwe render ai ищет шаблонные паки в таком порядке; используется первое совпадение:
workspace/templates/ai/<template>/(еслиtemplateзадан) — строго: пак должен существовать, иначе рендер падаетworkspace/templates/ai/<service-name>/(еслиtemplateне задан)workspace/templates/ai/default/(финальный фоллбэк)
Когда указан явный template:, а пак не найден, рендер падает с ошибкой (ловит опечатки). Когда явный шаблон не задан и неявная цепочка исчерпывается без нахождения пака, рендер пропускается с предупреждением.
После выбора пака команда читает manifest.yml пака, чтобы определить, какие файлы рендерить и какие симлинки создавать. Манифест объявляет:
render: исходные файлы шаблонов (должны оканчиваться на.tmpl) и их пути назначенияsymlinks: относительные симлинки для создания внутри hub сервиса (должны ссылаться на выводы изrender)
Все назначения относительны hub-каталога сервиса (например, services/main/). Вложенные пути допустимы (например, .claude/CLAUDE.md).
Разрешение коллизий
Заголовок раздела «Разрешение коллизий»Когда несколько сервисов разделяют один dir (например, main и main-debug, оба указывающие на ./services/main), только канонический владелец hub — наименее дочерний сервис (мельче всего в цепочке extends) — рендерит агент-документацию. Обоснование: агент-документация описывает идентичность hub, и когда потомок extends родителя и разделяет его dir, родитель владеет hub; потомок — runtime-вариант того же воркспейса. Проигравшие варианты отчитываются как пропущенные с предупреждением о коллизии.
Явная позиционная форма dwe render ai <service> трактует аргумент как якорь hub (так же, как render ide): аргумент валидируется как реальный сервис, затем разрешается через политику коллизий. Поэтому dwe render ai main-debug всё равно рендерит main, когда оба включены — вариант разрешается к каноническому владельцу hub.
(Примечание: это отличается от dwe render ide, где побеждает самая глубокая цепочка extends, потому что конфиги IDE — про per-variant переопределения.)
Разбор примера: раскладка шаблонного пака
Заголовок раздела «Разбор примера: раскладка шаблонного пака»Этот пример показывает, как организованы шаблонные паки агента и какие файлы получаются в каталоге сервиса.
Структура проекта:
workspace/services/ main/ service.ymlworkspace/templates/ai/ default/ manifest.yml AGENTS.md.tmpl .claude/CLAUDE.md.tmplМанифест (workspace/templates/ai/default/manifest.yml):
render: - from: AGENTS.md.tmpl to: AGENTS.md - from: .claude/CLAUDE.md.tmpl to: .claude/CLAUDE.md
symlinks: - link: CLAUDE.md to: AGENTS.mdПример шаблона (AGENTS.md.tmpl):
# {{.Service}} Service Hub
This is the {{.Service}} service running inside a DWE-managed hub.The application source code is at `src/`.
Service container: {{.ServiceCfg.Container}}Workspace root: {{.ServiceCfg.DirInternal}}Определение сервиса (workspace/services/main/service.yml):
type: appdir: ./services/main# render.ai.enabled по умолчанию true; рендерит, используя пак defaultПосле dwe render ai:
services/main/ AGENTS.md ← отрендерено из AGENTS.md.tmpl CLAUDE.md ← симлинк на AGENTS.md .claude/ CLAUDE.md ← отрендерено из .claude/CLAUDE.md.tmplБлок render.git
Заголовок раздела «Блок render.git»Управляет тем, рендерятся ли (и как именно) shell git-хуки в каталог src/.git/hooks/ сервиса из шаблонных паков.
render: git: enabled: true # opt-in для рендера git-хуков для этого сервиса template: custom-hooks # использовать пользовательский шаблонный пак| Поле | По умолчанию | Описание |
|---|---|---|
enabled | true для type: app; false иначе | Включить этот сервис в вывод dwe render git. Отражает политику по умолчанию render.ide. |
template | — | Необязательное имя каталога пользовательского шаблонного пака. Должно быть единственным ключом каталога под workspace/templates/git/ (без разделителей пути, без .., без абсолютных путей, без ведущей .). Если опущен, рендер откатывается к пакам, специфичным для имени сервиса, затем к default. Явные паки строгие: опечатка приведёт к ошибке, а не к молчаливому фоллбэку. |
Наследование extends для render.git.enabled и render.git.template следует тем же правилам, что render.ide и render.ai: явные значения потомка переопределяют родительские; опущенные значения наследуются. Разрешение коллизий на разделяемом dir использует deepest-extends-wins (так же, как render.ide).
Хуки записываются в <svc.Dir>/src/.git/hooks/<basename> с режимом 0755. Сервисы, у которых отсутствует src/.git (нет git-чекаута) или это файл (указатель worktree/submodule), пропускаются с предупреждением. См. render git для полного справочника, схемы манифеста и примеров.
Блок render.config
Заголовок раздела «Блок render.config»Управляет рендером конфигурационных файлов для этого сервиса — основанный на рендере преемник устаревшего механизма копирования configs:. Конфиги становятся чистыми выводами рендера из шаблонного пака, записываемыми прямо в дерево hub сервиса (обычно src/..., уже примонтированное как dir), переигрывая любые собранные значения generated.
render: config: template: laravel # необязательный пин пака; иначе соглашение + .local| Поле | По умолчанию | Описание |
|---|---|---|
template | — | Необязательное имя каталога пользовательского шаблонного пака под workspace/templates/config/<template>/. Когда задан, разрешение строгое (опечатка приводит к ошибке, а не к молчаливому фоллбэку). Когда опущен, разрешение идёт по цепочке имя сервиса → предки по extends → default, плюс соседнее переопределение <pack>.local/. |
В отличие от render.ide / ai / git, у render.config нет флага enabled — рендер конфигов гейтится исключительно тем, разрешается ли пак (opt-in: нет пака → нет рендера). Шаблоны конфигов используют сокращение ${...} (например, ${services.main.ports.http}, ${vars.databases.main}, ${generated.app_key}) — намеренное расхождение с сырым субстратом {{ }}, используемым другими видами рендера. См. render config для полного справочника, субстрата, схемы манифеста и потока harvest/replay.
Блок generated
Заголовок раздела «Блок generated»Объявляет per-service значения, генерируемые сервисом (Laravel APP_KEY, Magento crypt.key, …), которые DWE собирает обратно из собственного выходного файла сервиса в долговременное хранилище (.dwe/generated.yml) и переигрывает при каждом последующем рендере через пространство имён ${generated.<name>}. Модель — harvest, а не mint: значение генерирует сам сервис (например, php artisan key:generate); DWE лишь считывает его обратно как строку.
type: appdir: ./services/maingenerated: app_key: file: src/.env # выходной файл, относительно hub сервиса (svc.Dir) pattern: '^APP_KEY=(.*)$' # regex; группа захвата 1 = значение| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
file | string | да | Выходной файл, в который сервис записывает значение, относительно hub-каталога сервиса (svc.Dir). Должен быть содержащимся относительным путём (без ..). |
pattern | string | да | Regex, применяемый построчно; группа захвата 1 — собираемое значение. Должен компилироваться и объявлять ≥1 группу захвата. |
Ключ карты (app_key) — это идентификатор ${generated.<name>}. dwe validate отклоняет невалидный regex, отсутствие группы захвата, выходящий за пределы путь file или имя поля, которое не является валидным идентификатором ${generated.<name>}.
Шаг генерации сервиса обычно гейтится предикатом generated-missing <svc> <field>, так что он выполняется только при первом deploy (когда значение ещё не собрано), а затем собирается билтином service_generated_harvest. Значение переживает run / передеплой и сохраняется при reset, если не передан --clear-generated. См. render config для полного потока deploy, схемы хранилища и бутстрапа уже закоммиченного секрета через dwe render config <svc> --harvest.
Блок bridge
Заголовок раздела «Блок bridge»Подключает сервис к host-мосту — DWE монтирует небольшой статический shim dwe в контейнер, чтобы команды dwe (git-хуки, команды проекта, read-only диагностика) выполнялись изнутри контейнера, перенаправляясь на host-демона. Мост выключен по умолчанию для всех типов сервисов — включайте явно через enabled: true.
type: appdir: ./services/mainbridge: enabled: true # по умолчанию: false — мост строго opt-in # shim_path: /usr/local/bin/dwe # переопределение точки монтирования (коллизия base-образа) # on_unreachable: fail # fail | warn — политика shim, когда демон недоступен| Поле | Тип | Обязательно | По умолчанию | Описание |
|---|---|---|---|---|
enabled | bool (tristate) | нет | false (для всех типов) | Внедрить shim-бинарник и bridge-монтирования в контейнер этого сервиса. |
shim_path | string | нет | /usr/local/bin/dwe | Абсолютный путь в контейнере, куда монтируется shim; переопределите, если base-образ уже содержит файл там. |
on_unreachable | string | нет | fail | fail — shim печатает ошибку и выходит с кодом 1, когда host-демон недоступен (хук блокирует коммит); warn — печатает предупреждение и выходит с кодом 0. |
bridge.enabled — это tristate, наследуемый через extends: сервиса так же, как render.git.enabled: явное значение в потомке выигрывает, неустановленный потомок наследует родителя, а выключенное значение по умолчанию применяется, только если ни один из них не задан. shim_path и on_unreachable наследуются, когда потомок оставляет их пустыми. Сервис type: app с включённым мостом должен объявлять пару dir / dir_internal — поверх неё работает трансляция рабочей директории shim, и dwe validate (домен bridge) предупреждает, когда её нет. См. Host-мост для транспортов, in-container политики команд, генерируемого compose-оверлея и жизненного цикла демона.