Манифест плагина
Манифест — это файл dagstack.toml в корне папки плагина. Он декларирует метаданные плагина и требования к среде исполнения. Манифест — единственный источник истины для обнаружения: плагин без манифеста реестром не виден, даже если код корректен.
Минимальный манифест
[plugin]
name = "my-plugin"
kind = "tool"
runtime = "in_process"
core_version = ">=0.1.0,<1.0.0"
Этого достаточно для первой регистрации. Все опциональные поля — ниже.
Обязательные поля
| Поле | Тип | Описание |
|---|---|---|
name | строка | Имя плагина, уникальное в пределах kind. Строчные буквы, цифры, дефис, нижнее подчёркивание. |
kind | строка | Вид плагина — какой контракт он реализует. Примеры: llm, vector_store, chunker, pipeline, tool, orchestrator. |
runtime | строка или массив | Исполняющая среда: in_process, mcp_stdio, mcp_http. Допускается массив (плагин поддерживает несколько сред). |
core_version | строка | Требование к версии ядра dagstack-plugin-system, semver range. |
Опциональные поля
Метаинформация
[plugin]
name = "qdrant"
kind = "vector_store"
runtime = "in_process"
core_version = ">=0.1.0,<1.0.0"
version = "1.2.0"
description = "Vector store adapter for Qdrant."
authors = ["Dagstack Contributors"]
homepage = "https://example.org/qdrant-plugin"
license = "Apache-2.0"
Возможности (capabilities)
Используется диспетчером CapabilityDispatcher для выбора подходящего плагина под запрос. Возможности — произвольные строковые идентификаторы, семантика определяется видом.
[plugin]
name = "semantic-chunker"
kind = "chunker"
runtime = "in_process"
core_version = ">=0.1.0,<1.0.0"
capabilities = ["treesitter", "python", "typescript", "go"]
Ресурсы
Плагин декларирует, какие системные ресурсы ему нужны. Реестр подставляет их через inject_resources перед вызовом setup.
[plugin]
name = "sha-tagger"
kind = "tool"
runtime = "in_process"
core_version = ">=0.1.0,<1.0.0"
[plugin.resources]
required = ["Clock", "Rng", "BlobStore"]
В тестах стандартные ресурсы заменяются детерминированными: SystemClock → FrozenClock, RandomRng → DeterministicRng, InMemoryBlobStore остаётся.
Единица работы
Для плагинов, участвующих в оркестрации (Dagster, Celery, k8s), декларируется единица работы — набор ключей партиционирования и ожидаемая модель исполнения.
[plugin]
name = "file-indexer"
kind = "pipeline"
runtime = "in_process"
core_version = ">=0.1.0,<1.0.0"
execution_model = "async" # стиль исполнения хуков (sync | async | thread_cpu_bound | process_cpu_bound)
[plugin.unit_of_work]
declared = true
partition_key = "repo_id"
idempotency_mode = "input_hash" # input_hash | output_hash | none
checkpointable = true
content_hash = ["tenant_id", "repo_id", "file_sha"]
execution_model — это стиль исполнения хуков плагина (sync/async/CPU-bound), не класс диспетчеризации. Класс диспетчеризации (singleton, broadcast_collect, chain, capability) объявляется в hookspec вида плагина — в поле dispatch: каждого хука. См. ADR-0004 и Классы диспетчеризации.
partition_keys— поля, по которым оркестратор параллелит работу.idempotent— признак, что повторный запуск с тем жеcontent_hashдаст тот же результат (оркестратор может пропустить).content_hash— перечень полей для вычисления ключа идемпотентности.
Поддерживаемые возможности диспетчера
[plugin]
name = "openai-embedder"
kind = "embedder"
runtime = "in_process"
core_version = ">=0.1.0,<1.0.0"
supports_languages = ["en", "ru"]
supports_mime_types = ["text/plain"]
[plugin.supports]
text = true
image = false
batch = true
streaming = false
Поля supports_* используются CapabilityDispatcher для отбора плагинов под конкретный запрос. Решение, использовать ли capability-dispatch для хуков вида, принимается в hookspec вида в поле dispatch: — не в манифесте плагина.
Размещение манифеста в pyproject.toml (Python)
Для Python-плагинов, распространяемых как пакеты, допускается размещать содержимое манифеста в секции [tool.dagstack.plugin] файла pyproject.toml. Это удобно для публикуемых на PyPI плагинов, чтобы не дублировать метаданные.
[project]
name = "dagstack-plugin-openai"
version = "0.1.0"
[tool.dagstack.plugin]
name = "openai_compatible"
kind = "llm"
runtime = "in_process"
core_version = ">=0.1.0,<1.0.0"
Приоритет: если у плагина есть и dagstack.toml, и [tool.dagstack.plugin] в pyproject.toml, используется dagstack.toml.
Валидация
Валидация выполняется автоматически при discover. Вручную валидировать отдельный манифест можно так:
- Python
- TypeScript
- Go
from dagstack.plugin_system import load_manifest, assert_manifest_valid
from my_plugin import MyPlugin
manifest = load_manifest("plugins/my-plugin/dagstack.toml")
assert_manifest_valid(MyPlugin, manifest)
:::warning TypeScript runtime ships in Phase 1
@dagstack/plugin-system@0.1.0-rc.2 exports only the spec-emitted types — VERSION, ToolV1, OrchestratorV1. The runtime (PluginRegistry, discover, dispatchers, contract suite) lands in Phase 1. Today: implement the kind contract against the published types, then host plugins through Python over mcp_stdio or wait for the Phase 1 release. See the TypeScript API reference for the planned shape.
:::
manifest, err := pluginsystem.LoadManifestFromFile("plugins/my-plugin/dagstack.toml")
if err != nil {
return err
}
if err := manifest.Validate(); err != nil {
return err
}
Несоответствие схеме выбрасывает ManifestInvalid с путём к файлу и описанием первой ошибки валидации.