Пакеты каталога¶
Каталог Control Plane — это типы задач, типы артефактов, шаблоны проектов,
типы workspace, роли, capabilities, скиллы, правила вывода работы и описания
агентов; рядом с ними в пакете живут правила уведомлений сервиса уведомлений. Он
хранится в git как пакеты: YAML-файлы в
каталоге packages/ суперпроекта. Инструмент tools/cp_packages.py проверяет
пакеты без стенда, сверяет их с живым Control Plane и применяет. Статья для
администраторов инсталляции и авторов вертикальных пакетов. Обоснование
решения — TAI-ADR-0044.
Зачем пакеты¶
- Источник истины — git. Control Plane хранит опубликованные версии
объектов, а пакет говорит, какими они должны быть. Правка через API в обход
пакета видна:
planпокажет расхождение, аapplyопубликует версию из git поверх неё. - Воспроизводимость. Новая инсталляция получает каталог на шаге bootstrap, без ручных вызовов API.
- Одинаково для человека и машины. Файлы пишут руками, выгружают из
стенда командой
exportили генерируют из кода (скиллы, через skill-sdk). - Пакет — это данные. Формат и установщик относятся к ядру, содержимое пакетов — к домену.
Структура каталога packages/¶
packages/
├── README.md
├── schema/
│ └── v1/object.schema.json # JSON Schema 2020-12 формата
├── notify/ # уведомления (requires: [])
│ ├── package.yaml
│ ├── notification-rules/ # kind: NotificationRule — к сервису уведомлений
│ │ ├── approval-requested.yaml
│ │ ├── verification-failed.yaml
│ │ └── verification-blocked.yaml
│ └── skills/notify.send.yaml
├── sdd/ # цикл spec-driven (requires: [selfdev])
│ ├── agents/sdd-rules.yaml # личность правила feature-expand
│ ├── rules/feature-expand.yaml
│ └── task-types/ # feature-design, feature-tasks, feature-converge
└── selfdev/ # пакет саморазработки (requires: [])
├── package.yaml # манифест: kind: Package
├── agents/ # kind: Agent — исполнители, git-connector, selfdev-rules
├── task-types/
│ ├── coding-task.yaml # acceptance: review → merge
│ ├── submodule-bump.yaml # решение о сдвиге указателя сабмодуля
│ └── devops.yaml
├── rules/ # kind: WorkRule, identity: {agent: selfdev-rules}
│ ├── docs-drift.yaml
│ ├── submodule-lag.yaml
│ └── …
└── skills/
├── git.merge.yaml
├── git.bump_submodule.yaml
├── tasks.check.yaml
└── …
| Пакет | Что внутри | requires |
|---|---|---|
selfdev |
типы задач coding-task (приёмка типа: ревью человека → вливание git.merge@1), submodule-bump (решение: approve сдвигает указатель сабмодуля git.bump_submodule@1), devops, oss-publish; скиллы integrations/selfdev (git.merge@1, git.bump_submodule@1, tasks.check@1, проверки документации, ADR, миграций, авторизации, цикла spec-driven); правила вывода работы от имени агента selfdev-rules; агенты-исполнители, источник наблюдений git-connector и личность правил selfdev-rules. Переменные установки: SELFDEV_WORKSPACE_ID, SELFDEV_SUPERPROJECT_URL, SELFDEV_REVIEWER_PRINCIPAL и другие |
— |
sdd |
цикл spec-driven разработки: feature-design, feature-tasks (приёмка типа tasks.check@1), feature-converge, правило feature-expand от имени агента sdd-rules (см. Цикл spec-driven разработки) |
selfdev |
notify |
скилл notify.send@1 и правила уведомлений approval-requested, verification-failed, verification-blocked (см. Правила уведомлений); переменная установки TASK_URL_BASE |
— |
Файлы установки (какие пакеты ставить в конкретное окружение) лежат в
deploy/:
| Файл | Назначение |
|---|---|
deploy/packages.yaml |
установка по умолчанию, её использует make bootstrap (packages: [] — только системный тип task ядра) |
deploy/<окружение>/packages.yaml |
своя установка окружения со своим списком retire |
Формат объекта¶
Каждый файл — один объект в общей обёртке:
# yaml-language-server: $schema=../../schema/v1/object.schema.json
apiVersion: taimen.ai/v1
kind: TaskType
key: document-review
spec:
displayName: Document review
description: Проверка документа юристом.
fieldSchema: { ... }
lifecycleSchema: { ... }
approvalSchema: { ... }
acceptance: [ ... ]
| Поле | Правило |
|---|---|
apiVersion |
константа формата taimen.ai/v1 (идентификатор схемы, а не адрес сервиса) |
kind |
Package, Installation, ArtifactType, TaskType, ProjectTemplate, WorkspaceType, Role, Capability, Skill, WorkRule, Agent, NotificationRule |
key |
идентичность внутри tenant'а, 1–200 символов; у Package, ArtifactType, TaskType и ProjectTemplate — ^[a-z0-9][a-z0-9_-]*$, не длиннее 63; у Role и Agent — slug ^[a-z0-9][a-z0-9-]*$, 2–63 символа; у WorkRule и NotificationRule — ^[a-z0-9][a-z0-9._-]*$, до 128 символов |
spec |
ровно тело запроса API в camelCase, без поля идентичности: Control Plane, а для NotificationRule — сервиса уведомлений. Имена полей совпадают с OpenAPI сервиса |
Строка # yaml-language-server: $schema=… включает проверку и подсказки по
схеме в редакторе. Папки по видам (task-types/, skills/, …) — только
соглашение для людей. Вид объекта определяется полем kind, а не путём.
Отображение на API¶
| kind | Папка | Поле идентичности в API | Как применяется |
|---|---|---|---|
Package |
package.yaml |
каталог пакета | spec.version (SemVer), displayName, description, requires |
ArtifactType |
artifact-types/ |
key |
тип артефакта (см. ниже): версии неизменяемы и из оборота не выводятся; новая версия публикуется, только если файл отличается от новейшей версии |
TaskType |
task-types/ |
key |
версии неизменяемы: при расхождении с новейшей активной версией публикуется новая, остальные активные версии ключа переводятся в deprecated. Секция acceptance — критерии приёмки по умолчанию у всех задач типа (см. Приёмка типа) и участвует в сравнении |
ProjectTemplate |
project-templates/ |
key |
так же, как TaskType |
WorkspaceType |
workspace-types/ |
key |
создать или PATCH (с If-Match) при расхождении; архивный тип пакет не восстановит — это ошибка |
Role |
roles/ |
slug |
роли уровня tenant'а; создать или PATCH |
Capability |
capabilities/ |
name |
только создание; расхождение описания — предупреждение (API описание не меняет) |
Skill |
skills/ |
name + spec.version |
создать версию; расхождение в protocol, sideEffects, riskLevel или contract — ошибка «поднимите spec.version»; расхождение в description, config, inputSchema, outputSchema — PATCH, но ядро меняет у опубликованной версии только description (и статус), остальное отклоняет 409 skill_version_immutable |
Agent |
agents/ |
key |
агент (см. ниже): сначала POST /agents:validate; если не меняются ни ревизия, ни желаемое состояние — «без изменений», иначе POST /agents. Новая неизменяемая ревизия появляется, только если отличается хэш описания; state и placement.replicas меняют желаемое состояние без ревизии |
WorkRule |
rules/ |
key |
правило вывода работы (см. Правила вывода работы): создать или PATCH (с If-Match) изменённых description, trigger, condition, interpretation, action, identity; status (enabled/disabled, по умолчанию enabled) — через :enable/:disable. workspaceId задаётся только переменной установки (${NAME}) и после создания не меняется. С identity: {agent: <key>} правило действует полномочиями этого агента; без него — полномочиями того, чьим токеном применён пакет. Снятие identity из файла — PATCH identity: null |
NotificationRule |
notification-rules/ |
key |
правило уведомления (см. ниже): применяется к сервису уведомлений, а не к ядру; версию считает сервис по хэшу спецификации |
Calendar |
calendars/ |
key |
производственный календарь: выходные, праздники и переносы по годам; применяется только планом ядра (см. Процессы) |
Process |
processes/ |
key + spec.version |
процесс: стадии, шаги, таблицы решений, таймеры, данные по JSON Schema; применяется только планом ядра (см. Процессы) |
Удаления нет ни для одного вида. Порядок применения задан зависимостями:
WorkspaceType → Capability → Role → Skill → ArtifactType →
TaskType → Agent → ProjectTemplate → Calendar → Process → WorkRule →
NotificationRule. На
что ссылаются, то создаётся раньше: artifactSchema типа задачи ссылается на
типы артефактов, поэтому они публикуются до типов задач; агент ссылается на роли
и типы задач, поэтому идёт после них; правило с identity ссылается на агента.
Правила уведомлений ни на что в ядре не ссылаются, но исполняются сразу после
применения, поэтому идут последними — когда ядро уже приведено.
Агент (Agent)¶
Файл в папке agents/ описывает агента целиком: личность и права, какую работу
он берёт, вид исполнителя с параметрами и инструкциями, рабочую копию,
скиллы и размещение на узлах (TAI-ADR-0052). Схема — $defs.agentSpec в
packages/schema/v1/object.schema.json.
# yaml-language-server: $schema=../../schema/v1/object.schema.json
apiVersion: taimen.ai/v1
kind: Agent
key: reviewer
spec:
displayName: Code reviewer
identity:
kind: agent
permissions: [sessions.open, tasks.read, tasks.write, tasks.claim, artifacts.read, artifacts.write]
work:
workspace: ${AGENTS_WORKSPACE_ID}
taskTypes: [code-review]
executor:
kind: claude-code
params: {model: <model-id>, permissionMode: acceptEdits}
workingCopy:
repository: https://git.example.com/org/service.git
publish: false
placement:
requires: [repos]
secrets: [claude-oauth-token]
Особенности вида:
checkпроверяет описание схемой формата и модельюAgentSpecядра, требует, чтобыwork.taskTypesбыли объявлены в пакете или егоrequires, и предупреждает о ролях изidentity.roles, которых нет в пакетах (они должны уже быть в tenant'е);- топология —
work.workspace,work.project— пишется переменной установки${NAME}или UUID; - раздел
workingCopy.reviewустарел: ревью объявляет тип задачи критериями приёмки (см. Агенты описанием); - в описание не пишутся значения секретов — только имена в
placement.secrets; applyприменяет и желаемое состояние из файла (state,placement.replicas): агента, остановленного вручную, следующее применение запустит снова, если в файлеstate: running;retire.Agentв файле установки выводит агента из оборота: исполнитель останавливается, credential отзывается, история прогонов остаётся;exportвыгружаетspecтекущей (или указанной--version) ревизии, аstateиreplicas— из желаемого состояния, опуская умолчания.
Разделы описания, жизненный цикл ревизий и события — в статье Агенты описанием, размещение на машинах — в Узлах и fleet.
Правило уведомления (NotificationRule)¶
Файл в папке notification-rules/ описывает, какое событие Control Plane
становится уведомлением: событие и условие → адресат → тип, заголовок, текст,
ссылки, кнопки решения → закрытие кнопок по событию исхода. Схема —
$defs.notificationRuleSpec в packages/schema/v1/object.schema.json, полное
описание — в статье Правила уведомлений.
# yaml-language-server: $schema=../../schema/v1/object.schema.json
apiVersion: taimen.ai/v1
kind: NotificationRule
key: task-verified
spec:
"on": {type: task.verified}
recipient: {kind: taskOwner, fallback: taskAssignee}
notification:
type: task.verified
title: "Принято: {{task.publicId}} {{task.title}}"
links:
- {label: Открыть задачу, url: "${TASK_URL_BASE}/{{task.publicId}}"}
Особенности вида:
- применяется к сервису уведомлений: адрес — переменная установки
NOTIFICATION_SERVICE_URL, токен —NOTIFY_TOKEN(access token audiencenotification-service, scopenotifications:admin) или обмен того же IAM credential, что у установщика, на этот audience; - до первой записи — и в ядро, и в сервис — установщик вызывает
:validateдля всех правил установки: правило, которое сервис не примет, останавливает установку целиком; дальшеPOSTтолько изменившихся правил; - без
NOTIFICATION_SERVICE_URLapplyпропускает правила уведомлений с предупреждением (например, при bootstrap до шага сервиса уведомлений); - ключ
onпишется в кавычках ("on":) — иначе YAML 1.1 прочтёт его какtrue; retire.NotificationRuleвыводит правило из оборота (:retire), отправленные уведомления остаются;export --kind NotificationRuleвыгружает действующую версию из сервиса;--serverне нужен,--versionне поддерживается.
Тип артефакта (ArtifactType)¶
Файл в папке artifact-types/ объявляет тип артефакта — ключ, схему
metadata, допустимые media types и потолок размера содержимого (модель — в
Артефактах):
# yaml-language-server: $schema=../../schema/v1/object.schema.json
apiVersion: taimen.ai/v1
kind: ArtifactType
key: review-report
spec:
displayName: Заключение проверки
description: Заключение, которое сдаёт проверка и получает следующий шаг
mediaTypes: [application/pdf]
maxBytes: 10485760 # необязательно
metadataSchema:
type: object
properties:
reviewer: {type: string}
Поле spec |
Умолчание в пакете | Как сравнивается с живой версией |
|---|---|---|
displayName, description |
"" |
всегда |
metadataSchema |
{} |
всегда |
mediaTypes |
["*/*"] |
всегда; перед сравнением приводятся к нижнему регистру, параметры и повторы отбрасываются — так их хранит ядро |
maxBytes |
не задан — ядро берёт CP_ARTIFACT_MAX_BYTES инсталляции на момент публикации |
только если задан в файле |
Правила применения:
- версии неизменяемы, у API нет депрецирования типов артефактов, поэтому
applyне переводит старые версии вdeprecated, аretireдляArtifactTypeне поддерживается; - новая версия публикуется, только если хоть одно сравниваемое поле файла отличается от новейшей версии ключа; иначе — «без изменений»;
- артефакты всегда проверяются по новейшей версии, поэтому сужение
mediaTypesилиmaxBytesв новой версии сразу касается новых артефактов этого вида.
artifactSchema типа задачи (см. Входы и выходы)
ссылается на типы артефактов по ключу. Как и прочие ссылки, она замкнута:
тип артефакта должен быть объявлен в том же пакете или в пакете из
requires.
Манифест пакета¶
# yaml-language-server: $schema=../schema/v1/object.schema.json
apiVersion: taimen.ai/v1
kind: Package
key: selfdev
spec:
version: 0.1.0 # SemVer, обязательно
displayName: Self-development # обязательно
description: Доменные действия цикла саморазработки как скиллы.
requires: [] # пакеты, на объекты которых здесь ссылаются
Ключ пакета обязан совпадать с именем его каталога. Циклы в requires
запрещены.
Файл установки¶
# yaml-language-server: $schema=../../packages/schema/v1/object.schema.json
apiVersion: taimen.ai/v1
kind: Installation
key: production
spec:
packages: [selfdev, sdd] # requires подтягиваются сами
retire:
TaskType: [ops, analysis] # все активные версии → deprecated
retireописывает историю окружения, а не пакета. ПоддерживаютсяTaskType,ProjectTemplate(активные версии →deprecated),WorkRule(правило архивируется, заведённая им работа остаётся),Agent(:retire— исполнитель остановлен, credential отозван, ключ больше не используется) иNotificationRule(:retireв сервисе уведомлений, отправленные уведомления остаются).ArtifactTypeиз оборота не выводится.- Тип задачи, убранный из пакета, сам из оборота не выходит: добавьте его в
retire.TaskType, когда закрыты открытые задачи этого типа. Так выводится, например, прежний тип задачи ревью после перехода на приёмку типа. - Системный тип задачи
taskвывести из оборота нельзя: ядро всегда держит его активную версию. - Ключ не может одновременно быть объявлен в пакете и выводиться из оборота.
Правила содержимого¶
Ссылки — только по ключам, никогда по UUID. Примеры:
execution: {skill: git.merge, version: "1"}в типе задачи;ensureWork.type: coding-taskв исходе approval;invokeSkill.skill: git.merge@1в исходе approval;allowedChildTypes: [team]в типе workspace;artifactSchema.inputs[].type: spec-documentв типе задачи;identity: {agent: selfdev-rules}в правиле вывода работы;agent:<key>в полях назначения:ensureWork.assigneeисхода approval,fields.assigneeправила (см. Ссылка на агента).
Пакет замкнут: ссылка должна вести в сам пакет или в пакет из requires.
Единственное исключение — системный тип task. Для агентов (identity.agent
правила и литеральный agent:<key>) check дополнительно отвергает ссылку на
агента, которого та же установка выводит из оборота (retire.Agent). Ссылка
через шаблон ({{…}}, $.…) проверяется ядром при исполнении. Для allowedChildTypes
незамкнутая ссылка даёт предупреждение: такой тип должен уже существовать в
tenant'е.
Параметры окружения — ${NAME} в строковых значениях spec, например
адрес HTTP-скилла:
При plan и apply значение берётся из .env инсталляции (флаг --env, по
умолчанию .env в корне) и переменных процесса. Незаданная переменная — ошибка
установки. При check вместо незаданной переменной подставляется заглушка.
Секретов в пакете нет. Ядро само отвергает секретный материал в контрактах
и схемах (secret_material_rejected).
Скиллы генерируются из кода. YAML скилла не пишут руками: его генерирует
skill-sdk из декораторов в коде интеграции
(skill-sdk export --package packages/<пакет> <модуль>). Источник истины
контракта скилла — код, а расхождение ловит тест интеграции. Подробнее — в
skill-sdk.
Инструмент tools/cp_packages.py¶
python3 tools/cp_packages.py check [--install <файл> | --package <пакет>] [--server <url>] [--json]
python3 tools/cp_packages.py test (--install <файл> | --package <пакет>) --server <url> [--test <имя>] [--json]
python3 tools/cp_packages.py plan --install <файл> --server <url> [--env <.env>] [--out <plan.json>]
python3 tools/cp_packages.py apply --install <файл> --server <url> [--env <.env>]
python3 tools/cp_packages.py apply --plan <plan.json>
python3 tools/cp_packages.py migrate-expr --package <пакет> [--write]
python3 tools/cp_packages.py export --server <url> --kind <kind> --key <key> [--key ...] \
[--version <v>] --package packages/<пакет>
| Команда | Нужен стенд | Что делает |
|---|---|---|
check |
нет (с --server — да) |
проверяет все пакеты (без --install) или состав установки: схему формата, дубли, замкнутость ссылок, retire, тесты процессов, а также доменные валидаторы Control Plane; с --server — ещё и проверку процессов ядром |
test |
да | прогоняет тесты процессов пакета в песочнице ядра и печатает результат и покрытие |
plan |
да | сверяет установку с живым Control Plane и печатает, что изменится; ничего не пишет. С --out — план ядра с хэшем для apply --plan |
apply |
да | устанавливает: сначала check, при ошибках останавливается, затем применяет объекты по видам и retire; Process и Calendar пропускает — их применяет apply --plan |
migrate-expr |
нет | переводит прежние синтаксисы выражений пакета в CEL и печатает diff; --write записывает |
export |
да | выгружает объекты из живого Control Plane (для NotificationRule — из сервиса уведомлений) в файлы пакета (<package>/<папка вида>/<key>.yaml) |
Доменные валидаторы — те же функции, что ядро вызывает при создании объекта:
разбор жизненного цикла типа задачи, approvalSchema, execution,
artifactSchema, определения типа артефакта, контракта скилла, JSON Schema
полей, конфигурации и governance шаблонов проекта.
Для типов артефактов и artifactSchema check дополнительно проверяет:
- определение
ArtifactType— схемуmetadataSchema, грамматикуmediaTypes, положительныйmaxBytes. ПотолокCP_ARTIFACT_MAX_BYTESзнает только инсталляция, поэтому превышение его ловит уже ядро приapply(422 invalid_artifact_type); - грамматику
artifactSchema(поля слотов,from,content, ключи); - что каждый
typeвхода и выхода объявлен какArtifactTypeв пакете или егоrequires; - что
mediaTypesвыхода сужаетmediaTypesсвоего типа артефакта. Их берут из сабмодуляcontrol-plane. Если он не импортируется (нет сабмодуля илиjsonschema),checkвыдаёт предупреждение и проверяет только схему формата. Для работы нужныPyYAMLиjsonschema.
Credential для plan, apply, export¶
Инструмент ходит в API с Authorization: Bearer <token>. Токен берётся:
- из переменной
CP_TOKEN— access token IAM audiencecontrol-plane; - если её нет — из credential
control_plane_client, то есть из той же IAM-identity, что у CLI и MCP-сервера (см. CLI и MCP-сервер). Для этого скрипт нужно запускать интерпретатором окружения, где установлен пакетcontrol-plane.
Токену нужны права на запись каталога: task_types.manage,
artifact_types.manage,
project_templates.manage, workspaces.manage, org.manage (роли,
capabilities, скиллы), agents.manage (агенты), rules.write (правила), а
также соответствующие права чтения. Права, которые описание агента выдаёт
агенту, должны быть у самого токена: иначе 403 permission_escalation. То же
для правил с identity: применяющий должен иметь все права агента-личности.
Для NotificationRule нужен второй токен — audience notification-service,
scope notifications:admin: переменная NOTIFY_TOKEN или обмен того же IAM
credential (PAT должен допускать этот audience в потолке, иначе IAM ответит
iam_audience_not_allowed).
Проверка в CI: make packages-check¶
Цель выполняет две проверки:
python3 tools/cp_packages.py check
python3 tools/cp_packages.py check --install deploy/staging/packages.yaml
Вывод:
или список строк ошибка: <файл>: <сообщение> с кодом выхода 1.
Процессы и календари¶
Процесс (kind: Process) и производственный календарь (kind: Calendar)
исполняет и проверяет само ядро Control Plane (обоснование — TAI-ADR-0054,
CP-ADR-0074). Язык процессов описан в разделе Процессы,
тесты и план — в Тестах пакета. Локальной копии движка нет: без ядра check проверяет только
форму по схеме, ссылки и тесты пакета.
Нужен Control Plane с движком процессов
Команды test, plan --out и apply --plan, а также check --server
обращаются к маршрутам POST /api/v1/packages:test, /packages:plan и
/packages:apply. Если ядро их не знает (404) или ещё не реализует
(501 not_implemented), check --server сообщает «ядро не поддерживает
проверку процессов … — проверена только схема» и завершается по
статической проверке, а остальные команды — ошибкой.
Раскладка пакета с процессом¶
packages/<пакет>/
├── package.yaml # renames — явные переименования объектов
├── processes/<ключ>.yaml # kind: Process
├── calendars/<ключ>.yaml # kind: Calendar
├── schemas/<имя>.schema.json # схемы данных: data: {$ref: ../schemas/<имя>.schema.json}
├── tests/<имя>.test.yaml # тесты процессов (schema/v1/test.schema.json)
└── .layout/<ключ>.json # раскладка схемы для визуального редактора
data: {$ref: …} ссылается только на файл внутри пакета. Раскладка ядру не
отправляется и логики не несёт.
Проверка, тесты, план, применение¶
python3 tools/cp_packages.py check --package packages/<пакет> --server https://platform.example.com --json
python3 tools/cp_packages.py test --package packages/<пакет> --server https://platform.example.com
python3 tools/cp_packages.py plan --install deploy/<окружение>/packages.yaml \
--server https://platform.example.com --out plan.json
python3 tools/cp_packages.py apply --plan plan.json
Каждый запрос — один пакет своими файлами: {package: {files: [{path,
content}]}}, вместе с tests/ и без .layout/, с подставленными
переменными установки. Пакеты из requires ядро берёт из своего каталога,
переименования — из renames в package.yaml.
check --serverпроверяет названные пакеты запросомPOST /packages:test?checkOnly=true. Находки ядра печатаются какфайл:строка: код: сообщение [путь] (подсказка: …); с--json— список объектов{code, severity, path, file, line, message, hint}.testпечатает по каждому тестуok/FAIL, шаг и причину падения, а затем покрытие процесса: элементы, переходы, строки таблиц решений, обработчики ошибок — и что не пройдено. Код выхода1, если есть упавшие тесты.plan --outпоказывает структурный diff (+добавится,~изменится,-выводится,→переименование), владельца поля (правленное в консоли не перезаписывается), расхождения поведения по replay и судьбу открытых экземпляров (pin— дорабатывают на своей версии,migrate— переходят по карте), покрытие разделов регламентов. План строится по каждому пакету установки (--replay-limit— сколько экземпляров прогнать replay, по умолчанию 50) и сохраняется в файл вместе с хэшами; план с ошибками (напримерmigration_required) не сохраняется.retireфайла установки в план ядра не входит — его выполняет обычныйapply --install.apply --planотправляет по каждому пакету те же файлы, по которым строился план, и егоplanHash. Если каталог стенда успел измениться, ядро отвечаетplan_stale— план строится заново. Файл плана, изменённый после построения, не применяется; план, построенный для другого адреса, тоже.
Правка файлов: tools/pkg.py¶
tools/pkg.py выполняет мелкие правки процесса и пакета и меняет только
затронутые строки: комментарии, порядок ключей, кавычки и flow/block-стиль
остального файла остаются как были. Нужен пакет ruamel.yaml.
| Операция | Что делает |
|---|---|
add-step --in <стадия или шаг> --step <yaml> [--after/--before <id>] |
добавляет шаг в стадию или в блок do шага, ветви, таймера |
add-stage --stage <yaml> [--after/--before <id>] |
добавляет стадию |
add-decision-row --table <id> --row <yaml> [--index N] |
добавляет строку таблицы решений; столбцы проверяются по входам и выходам таблицы |
add-rule --table <id> --row <yaml> или add-rule --on-event <yaml> |
правило: строка таблицы решений или реакция процесса на событие (onEvent) |
add-form-field --step <id> --name <поле> --schema <yaml> [--required] [--label] |
поле формы человеческого шага (и элемент uischema, если он есть) |
rename --file <процесс> --from <id> --to <id> [--no-migration] |
переименовывает элемент процесса, ссылки на него и тесты пакета; дописывает карту migrations и переносит координаты раскладки |
rename --package <каталог> --kind Process --from <ключ> --to <ключ> |
переименовывает объект пакета и файл, дописывает renames в package.yaml |
set --path <путь> --value <yaml> |
записывает значение; в пути [N] — индекс, [id] — элемент списка по id |
Флаг --json печатает результат или ошибку машиночитаемо
({"ok": false, "error": {"code", "message", "path", "hint"}}), --dry-run —
diff без записи. Правка, которую не пропускает схема каталога или которая
повторяет id элемента, не записывается.
Загрузка и запись файла без изменений дают тот же файл байт в байт: стиль
файла (отступы, смещение -, ширина строки, запись null) подбирается при
загрузке. Переносы строк внутри flow-коллекции ({a: 1, и b: 2} на разных
строках) ruamel.yaml не хранит — такую правку pkg.py переносит на исходный
текст слиянием, и остальные строки файла не меняются.
Язык пакетов — YAML 1.2: булевы значения только true/false, ключи on,
off, yes, no — строки.
Как применяется каталог¶
При bootstrap¶
deploy/bootstrap.py применяет пакеты на шаге 5b через
cp_packages.apply(). По умолчанию используется файл
deploy/packages.yaml, другой файл передаётся флагом:
Идентификаторы опубликованных объектов сохраняются в state bootstrap
(deploy/state/<имя>.json). В самих пакетах UUID не живут. Подробности —
в статье Bootstrap.
Вручную на работающей инсталляции¶
# 1. Проверить без стенда
make packages-check
# 2. Посмотреть план
export CP_TOKEN=<access-token audience control-plane>
python3 tools/cp_packages.py plan \
--install deploy/production/packages.yaml \
--server https://platform.example.com
# 3. Применить
python3 tools/cp_packages.py apply \
--install deploy/production/packages.yaml \
--server https://platform.example.com
Пример вывода plan:
пакеты: notify 0.2.0, selfdev 0.16.0
TaskType/coding-task: (план) новая версия (изменились acceptance)
TaskType/coding-task: (план) v5 → deprecated
Skill/git.bump_submodule@1: (план) будет зарегистрирован
WorkRule/submodule-lag: (план) изменятся identity
NotificationRule/approval-requested: (план) v1 без изменений
TaskType/ops: v1 → deprecated (retire)
Задачи на старых версиях не меняются
Новая версия типа задачи и перевод старой в deprecated не затрагивают
уже созданные задачи: они продолжают жить на своей версии. Новые задачи
по ключу получают новейшую активную версию.
Перенос ручных правок в git¶
Объект, который завели или поправили через API, выгружается в пакет:
python3 tools/cp_packages.py export \
--server https://platform.example.com \
--kind TaskType --key support_case \
--package packages/support
export берёт новейшую активную версию (или ту, что указана в --version),
отбрасывает пустые поля и значения по умолчанию, а у скилла с контрактом
убирает поля, которые выводятся из контракта (inputSchema, outputSchema,
protocol).
Новый пакет — пошагово¶
- Создайте
packages/<key>/package.yamlсkind: Package. Ключ совпадает с именем каталога. - Положите объекты по одному в файл. Проще всего начать с
exportсуществующего объекта. - Если пакет ссылается на объекты другого пакета, перечислите его в
requires. - Запустите
make packages-check. - Добавьте ключ пакета в
spec.packagesфайла установки окружения. - Выполните
plan, затемapply(или повторный bootstrap).
Что в пакет не входит¶
- Топология: workspaces, проекты, членство и назначения ролей людям.
Это данные окружения (state bootstrap), а не каталог. Principals и связки
агентов в пакет тоже не пишутся: их выводит платформа из описания
Agent. - Задачи-фикстуры.
- Доменные пакеты онтологии памяти регистрируются в memory-service отдельно, см. Контекст задачи и память.
Типичные проблемы¶
| Сообщение | Причина | Что делать |
|---|---|---|
нужен PyYAML / нужен jsonschema |
нет зависимостей | pip install pyyaml jsonschema |
доменные валидаторы control-plane не импортируются |
нет сабмодуля control-plane |
git submodule update --init |
execution ссылается на Skill …, которого нет ни в пакете …, ни в его requires |
незамкнутая ссылка | добавить пакет со скиллом в requires или перенести скилл |
в опубликованной версии отличаются contract — контракт версии неизменяем |
правили контракт без смены версии | поднять spec.version скилла |
переменная окружения X не задана (нужна пакету) |
нет значения для ${X} |
задать в .env или окружении |
retire: системный тип task вывести нельзя |
task в retire |
убрать из списка |
artifactSchema.inputs 'spec': тип артефакта 'spec-document' не объявлен ни в пакете …, ни в его requires |
незамкнутая ссылка на тип артефакта | объявить ArtifactType в пакете или добавить пакет с ним в requires |
artifactSchema.outputs '…': mediaTypes [...] шире, чем у типа … |
выход расширяет, а не сужает media types типа | сузить mediaTypes выхода или расширить тип артефакта |
retire: вид ArtifactType не выводится из оборота |
ArtifactType в retire |
убрать из списка |
ядро не принимает описание агента: … |
описание Agent не проходит модель AgentSpec ядра (неизвестное поле, пустые permissions) |
исправить описание по сообщению |
422 non_canonical_value при apply агента |
в описании число с плавающей точкой (например дробное resources.cpus) |
только целые числа |
identity.agent ссылается на агента … / … — такого Agent нет в пакете |
правило или назначение ссылается на агента вне пакета и его requires или выводимого из оборота |
описать агента в пакете или добавить пакет в requires |
NotificationRule не применены: не задан сервис уведомлений |
нет NOTIFICATION_SERVICE_URL или токена |
задать переменную и NOTIFY_TOKEN |
сервис уведомлений не принимает правило — … |
:validate вернул 422 invalid_notification_rule |
исправить правило по details.errors |
work.taskTypes '…' — такого TaskType нет в пакете … |
агент ссылается на тип задачи вне пакета и его requires |
объявить тип или добавить пакет в requires |
403 permission_escalation при apply агента |
у токена нет прав, которые описание выдаёт агенту | применять токеном с этими правами |
нет CP_TOKEN и нет control_plane_client |
нет credential | задать CP_TOKEN или запустить интерпретатором с установленным control-plane |
control-plane не сохранил execution |
релиз ядра не поддерживает execution у типа задачи |
обновить Control Plane |
ядро не поддерживает проверку процессов, только схема / ядро не знает /packages:plan |
Control Plane без движка процессов | обновить Control Plane; до этого процессы проверяются только схемой |
план устарел: каталог стенда изменился после построения плана |
ответ plan_stale на apply --plan |
построить план заново и применить новый |
план правили после построения (хэш не сходится) |
файл плана изменён руками | построить план заново |
…: процессы и календари применяет ядро по плану |
в установке есть Process или Calendar, а вызван обычный apply |
plan --out plan.json, затем apply --plan plan.json |
element_id_taken от pkg.py |
id элемента уже есть в процессе | выбрать другой id |
См. также¶
- Процессы — язык вида
Process - Тесты пакета — проверка, тесты, replay, план
- Типы задач и статусы
- Агенты описанием
- Правила вывода работы
- Правила уведомлений
- Цикл spec-driven разработки
- Артефакты и комментарии — реестр типов артефактов
- Approvals
- Bootstrap
- skill-sdk
- Вертикальные пакеты
- Цели make